Page Menu
Home
GnuPG
Search
Configure Global Search
Log In
Files
F36276297
protocol.c
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Size
99 KB
Subscribers
None
protocol.c
View Options
/* protocol.c - TLS 1.2 protocol implementation
* Copyright (C) 2006-2014, Brainspark B.V.
* Copyright (C) 2014 g10 code GmbH
*
* This file is part of NTBTLS
*
* NTBTLS is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* NTBTLS is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*
* This file was part of PolarSSL (http://www.polarssl.org). Former
* Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>.
* Please do not file bug reports to them but to the address given in
* the file AUTHORS in the top directory of NTBTLS.
*/
#include
<config.h>
#include
<stdlib.h>
#include
"ntbtls-int.h"
static
void
session_free
(
session_t
session
);
static
void
update_checksum_start
(
ntbtls_t
,
const
unsigned
char
*
,
size_t
);
static
void
update_checksum_sha256
(
ntbtls_t
,
const
unsigned
char
*
,
size_t
);
static
void
calc_verify_tls_sha256
(
ntbtls_t
,
unsigned
char
*
);
static
void
calc_finished_tls_sha256
(
ntbtls_t
,
unsigned
char
*
,
int
);
static
void
update_checksum_sha384
(
ntbtls_t
,
const
unsigned
char
*
,
size_t
);
static
void
calc_verify_tls_sha384
(
ntbtls_t
,
unsigned
char
*
);
static
void
calc_finished_tls_sha384
(
ntbtls_t
,
unsigned
char
*
,
int
);
/*
* Convert max_fragment_length codes to length.
* RFC 6066 says:
* enum{
* 2^9(1), 2^10(2), 2^11(3), 2^12(4), (255)
* } MaxFragmentLength;
* and we add 0 -> extension unused
*/
static
unsigned
int
mfl_code_to_length
[
TLS_MAX_FRAG_LEN_INVALID
]
=
{
TLS_MAX_CONTENT_LEN
,
/* SSL_MAX_FRAG_LEN_NONE */
512
,
/* SSL_MAX_FRAG_LEN_512 */
1024
,
/* SSL_MAX_FRAG_LEN_1024 */
2048
,
/* SSL_MAX_FRAG_LEN_2048 */
4096
/* SSL_MAX_FRAG_LEN_4096 */
};
static
int
ssl_session_copy
(
session_t
dst
,
const
session_t
src
)
{
session_free
(
dst
);
memcpy
(
dst
,
src
,
sizeof
*
src
);
if
(
src
->
peer_cert
)
{
/* int ret; */
//FIXME: Use libksba
/* dst->peer_cert = malloc (sizeof *dst->peer_cert); */
/* if (!dst->peer_cert) */
/* return gpg_error_from_syserror (); */
/* x509_crt_init (dst->peer_cert); */
/* if ((ret = x509_crt_parse_der (dst->peer_cert, src->peer_cert->raw.p, */
/* src->peer_cert->raw.len)) != 0) */
/* { */
/* free (dst->peer_cert); */
/* dst->peer_cert = NULL; */
/* return (ret); */
/* } */
}
if
(
src
->
ticket
)
{
dst
->
ticket
=
malloc
(
src
->
ticket_len
);
if
(
!
dst
->
ticket
)
return
gpg_error_from_syserror
();
memcpy
(
dst
->
ticket
,
src
->
ticket
,
src
->
ticket_len
);
}
return
(
0
);
}
/*
* output = HMAC-SHA-NNN( hmac key, input buffer )
*
* The used algorithm depends on OUTPUTSIZE which is expected in bytes.
*/
static
gpg_error_t
sha_hmac
(
const
unsigned
char
*
key
,
size_t
keylen
,
const
unsigned
char
*
input
,
size_t
inputlen
,
unsigned
char
*
output
,
int
outputsize
)
{
gpg_error_t
err
;
gcry_mac_hd_t
hd
;
size_t
macoutlen
;
int
algo
;
switch
(
outputsize
)
{
case
32
:
algo
=
GCRY_MAC_HMAC_SHA256
;
break
;
case
48
:
algo
=
GCRY_MAC_HMAC_SHA384
;
break
;
case
64
:
algo
=
GCRY_MAC_HMAC_SHA512
;
break
;
default
:
return
gpg_error
(
GPG_ERR_MAC_ALGO
);
}
err
=
gcry_mac_open
(
&
hd
,
algo
,
0
,
NULL
);
if
(
!
err
)
{
err
=
gcry_mac_setkey
(
hd
,
key
,
keylen
);
if
(
!
err
)
{
err
=
gcry_mac_write
(
hd
,
input
,
inputlen
);
if
(
!
err
)
{
macoutlen
=
outputsize
;
err
=
gcry_mac_read
(
hd
,
output
,
&
macoutlen
);
}
}
gcry_mac_close
(
hd
);
}
return
err
;
}
/*
* Key material generation
*/
static
int
tls_prf_sha256
(
const
unsigned
char
*
secret
,
size_t
slen
,
const
char
*
label
,
const
unsigned
char
*
random
,
size_t
rlen
,
unsigned
char
*
dstbuf
,
size_t
dlen
)
{
gpg_error_t
err
;
size_t
nb
;
size_t
i
,
j
,
k
;
unsigned
char
tmp
[
128
];
unsigned
char
h_i
[
32
];
if
(
sizeof
(
tmp
)
<
32
+
strlen
(
label
)
+
rlen
)
return
gpg_error
(
GPG_ERR_INV_ARG
);
nb
=
strlen
(
label
);
memcpy
(
tmp
+
32
,
label
,
nb
);
memcpy
(
tmp
+
32
+
nb
,
random
,
rlen
);
nb
+=
rlen
;
/*
* Compute P_<hash>(secret, label + random)[0..dlen]
*/
err
=
sha_hmac
(
secret
,
slen
,
tmp
+
32
,
nb
,
tmp
,
32
);
if
(
err
)
return
err
;
for
(
i
=
0
;
i
<
dlen
;
i
+=
32
)
{
err
=
sha_hmac
(
secret
,
slen
,
tmp
,
32
+
nb
,
h_i
,
32
);
if
(
err
)
return
err
;
err
=
sha_hmac
(
secret
,
slen
,
tmp
,
32
,
tmp
,
32
);
if
(
err
)
return
err
;
k
=
(
i
+
32
>
dlen
)
?
dlen
%
32
:
32
;
for
(
j
=
0
;
j
<
k
;
j
++
)
dstbuf
[
i
+
j
]
=
h_i
[
j
];
}
wipememory
(
tmp
,
sizeof
(
tmp
));
wipememory
(
h_i
,
sizeof
(
h_i
));
return
0
;
}
static
int
tls_prf_sha384
(
const
unsigned
char
*
secret
,
size_t
slen
,
const
char
*
label
,
const
unsigned
char
*
random
,
size_t
rlen
,
unsigned
char
*
dstbuf
,
size_t
dlen
)
{
gpg_error_t
err
;
size_t
nb
;
size_t
i
,
j
,
k
;
unsigned
char
tmp
[
128
];
unsigned
char
h_i
[
48
];
if
(
sizeof
(
tmp
)
<
48
+
strlen
(
label
)
+
rlen
)
return
gpg_error
(
GPG_ERR_INV_ARG
);
nb
=
strlen
(
label
);
memcpy
(
tmp
+
48
,
label
,
nb
);
memcpy
(
tmp
+
48
+
nb
,
random
,
rlen
);
nb
+=
rlen
;
/*
* Compute P_<hash>(secret, label + random)[0..dlen]
*/
err
=
sha_hmac
(
secret
,
slen
,
tmp
+
48
,
nb
,
tmp
,
48
);
if
(
err
)
return
err
;
for
(
i
=
0
;
i
<
dlen
;
i
+=
48
)
{
err
=
sha_hmac
(
secret
,
slen
,
tmp
,
48
+
nb
,
h_i
,
48
);
if
(
err
)
return
err
;
err
=
sha_hmac
(
secret
,
slen
,
tmp
,
48
,
tmp
,
48
);
if
(
err
)
return
err
;
k
=
(
i
+
48
>
dlen
)
?
dlen
%
48
:
48
;
for
(
j
=
0
;
j
<
k
;
j
++
)
dstbuf
[
i
+
j
]
=
h_i
[
j
];
}
wipememory
(
tmp
,
sizeof
(
tmp
));
wipememory
(
h_i
,
sizeof
(
h_i
));
return
(
0
);
}
gpg_error_t
_ntbtls_derive_keys
(
ntbtls_t
ssl
)
{
int
ret
=
0
;
unsigned
char
tmp
[
64
];
unsigned
char
keyblk
[
256
];
unsigned
char
*
key1
;
unsigned
char
*
key2
;
unsigned
char
*
mac_enc
;
unsigned
char
*
mac_dec
;
size_t
iv_copy_len
;
const
cipher_info_t
*
cipher_info
;
const
md_info_t
*
md_info
;
session_t
session
=
ssl
->
session_negotiate
;
ssl_transform
*
transform
=
ssl
->
transform_negotiate
;
ssl_handshake_params
*
handshake
=
ssl
->
handshake
;
debug_msg
(
2
,
"=> derive keys"
);
cipher_info
=
cipher_info_from_type
(
transform
->
ciphersuite_info
->
cipher
);
if
(
cipher_info
==
NULL
)
{
debug_msg
(
1
,
"cipher info for %d not found"
,
transform
->
ciphersuite_info
->
cipher
);
return
(
POLARSSL_ERR_SSL_BAD_INPUT_DATA
);
}
md_info
=
md_info_from_type
(
transform
->
ciphersuite_info
->
mac
);
if
(
md_info
==
NULL
)
{
debug_msg
(
1
,
"md info for %d not found"
,
transform
->
ciphersuite_info
->
mac
);
return
(
POLARSSL_ERR_SSL_BAD_INPUT_DATA
);
}
/*
* Set appropriate PRF function and other TLS functions
*/
if
(
ssl
->
minor_ver
==
SSL_MINOR_VERSION_3
&&
transform
->
ciphersuite_info
->
mac
==
GCRY_MD_SHA384
)
{
handshake
->
tls_prf
=
tls_prf_sha384
;
handshake
->
calc_verify
=
calc_verify_tls_sha384
;
handshake
->
calc_finished
=
calc_finished_tls_sha384
;
}
else
if
(
ssl
->
minor_ver
==
SSL_MINOR_VERSION_3
)
{
handshake
->
tls_prf
=
tls_prf_sha256
;
handshake
->
calc_verify
=
calc_verify_tls_sha256
;
handshake
->
calc_finished
=
calc_finished_tls_sha256
;
}
else
{
debug_bug
();
return
(
POLARSSL_ERR_SSL_INTERNAL_ERROR
);
}
/*
* TLSv1+:
* master = PRF( premaster, "master secret", randbytes )[0..47]
*/
if
(
handshake
->
resume
==
0
)
{
debug_buf
(
3
,
"premaster secret"
,
handshake
->
premaster
,
handshake
->
pmslen
);
handshake
->
tls_prf
(
handshake
->
premaster
,
handshake
->
pmslen
,
"master secret"
,
handshake
->
randbytes
,
64
,
session
->
master
,
48
);
wipememory
(
handshake
->
premaster
,
sizeof
(
handshake
->
premaster
));
}
else
debug_msg
(
3
,
"no premaster (session resumed)"
);
/*
* Swap the client and server random values.
*/
memcpy
(
tmp
,
handshake
->
randbytes
,
64
);
memcpy
(
handshake
->
randbytes
,
tmp
+
32
,
32
);
memcpy
(
handshake
->
randbytes
+
32
,
tmp
,
32
);
wipememory
(
tmp
,
sizeof
(
tmp
));
/*
* TLSv1:
* key block = PRF( master, "key expansion", randbytes )
*/
handshake
->
tls_prf
(
session
->
master
,
48
,
"key expansion"
,
handshake
->
randbytes
,
64
,
keyblk
,
256
);
debug_msg
(
3
,
"ciphersuite = %s"
,
ssl_get_ciphersuite_name
(
session
->
ciphersuite
));
debug_buf
(
3
,
"master secret"
,
session
->
master
,
48
);
debug_buf
(
4
,
"random bytes"
,
handshake
->
randbytes
,
64
);
debug_buf
(
4
,
"key block"
,
keyblk
,
256
);
wipememory
(
handshake
->
randbytes
,
sizeof
(
handshake
->
randbytes
));
/*
* Determine the appropriate key, IV and MAC length.
*/
transform
->
keylen
=
cipher_info
->
key_length
/
8
;
if
(
cipher_info
->
mode
==
POLARSSL_MODE_GCM
||
cipher_info
->
mode
==
POLARSSL_MODE_CCM
)
{
transform
->
maclen
=
0
;
transform
->
ivlen
=
12
;
transform
->
fixed_ivlen
=
4
;
/* Minimum length is expicit IV + tag */
transform
->
minlen
=
transform
->
ivlen
-
transform
->
fixed_ivlen
+
(
transform
->
ciphersuite_info
->
flags
&
POLARSSL_CIPHERSUITE_SHORT_TAG
?
8
:
16
);
}
else
{
int
ret
;
/* Initialize HMAC contexts */
if
((
ret
=
md_init_ctx
(
&
transform
->
md_ctx_enc
,
md_info
))
!=
0
||
(
ret
=
md_init_ctx
(
&
transform
->
md_ctx_dec
,
md_info
))
!=
0
)
{
SSL_DEBUG_RET
(
1
,
"md_init_ctx"
,
ret
);
return
(
ret
);
}
/* Get MAC length */
transform
->
maclen
=
md_get_size
(
md_info
);
/*
* If HMAC is to be truncated, we shall keep the leftmost bytes,
* (rfc 6066 page 13 or rfc 2104 section 4),
* so we only need to adjust the length here.
*/
if
(
session
->
trunc_hmac
==
SSL_TRUNC_HMAC_ENABLED
)
transform
->
maclen
=
SSL_TRUNCATED_HMAC_LEN
;
/* IV length */
transform
->
ivlen
=
cipher_info
->
iv_size
;
/* Minimum length */
if
(
cipher_info
->
mode
==
POLARSSL_MODE_STREAM
)
transform
->
minlen
=
transform
->
maclen
;
else
{
/*
* GenericBlockCipher:
* first multiple of blocklen greater than maclen
* + IV except for SSL3 and TLS 1.0
*/
transform
->
minlen
=
(
transform
->
maclen
+
cipher_info
->
block_size
-
transform
->
maclen
%
cipher_info
->
block_size
);
if
(
ssl
->
minor_ver
==
SSL_MINOR_VERSION_2
||
ssl
->
minor_ver
==
SSL_MINOR_VERSION_3
)
{
transform
->
minlen
+=
transform
->
ivlen
;
}
else
{
debug_bug
();
return
(
POLARSSL_ERR_SSL_INTERNAL_ERROR
);
}
}
}
debug_msg
(
3
,
"keylen: %d, minlen: %d, ivlen: %d, maclen: %d"
,
transform
->
keylen
,
transform
->
minlen
,
transform
->
ivlen
,
transform
->
maclen
);
/*
* Finally setup the cipher contexts, IVs and MAC secrets.
*/
if
(
tls
->
is_client
)
{
key1
=
keyblk
+
transform
->
maclen
*
2
;
key2
=
keyblk
+
transform
->
maclen
*
2
+
transform
->
keylen
;
mac_enc
=
keyblk
;
mac_dec
=
keyblk
+
transform
->
maclen
;
/*
* This is not used in TLS v1.1.
*/
iv_copy_len
=
(
transform
->
fixed_ivlen
)
?
transform
->
fixed_ivlen
:
transform
->
ivlen
;
memcpy
(
transform
->
iv_enc
,
key2
+
transform
->
keylen
,
iv_copy_len
);
memcpy
(
transform
->
iv_dec
,
key2
+
transform
->
keylen
+
iv_copy_len
,
iv_copy_len
);
}
else
{
key1
=
keyblk
+
transform
->
maclen
*
2
+
transform
->
keylen
;
key2
=
keyblk
+
transform
->
maclen
*
2
;
mac_enc
=
keyblk
+
transform
->
maclen
;
mac_dec
=
keyblk
;
/*
* This is not used in TLS v1.1.
*/
iv_copy_len
=
(
transform
->
fixed_ivlen
)
?
transform
->
fixed_ivlen
:
transform
->
ivlen
;
memcpy
(
transform
->
iv_dec
,
key1
+
transform
->
keylen
,
iv_copy_len
);
memcpy
(
transform
->
iv_enc
,
key1
+
transform
->
keylen
+
iv_copy_len
,
iv_copy_len
);
}
if
(
ssl
->
minor_ver
>=
SSL_MINOR_VERSION_1
)
{
md_hmac_starts
(
&
transform
->
md_ctx_enc
,
mac_enc
,
transform
->
maclen
);
md_hmac_starts
(
&
transform
->
md_ctx_dec
,
mac_dec
,
transform
->
maclen
);
}
else
{
debug_bug
();
return
(
POLARSSL_ERR_SSL_INTERNAL_ERROR
);
}
if
((
ret
=
cipher_init_ctx
(
&
transform
->
cipher_ctx_enc
,
cipher_info
))
!=
0
)
{
SSL_DEBUG_RET
(
1
,
"cipher_init_ctx"
,
ret
);
return
(
ret
);
}
if
((
ret
=
cipher_init_ctx
(
&
transform
->
cipher_ctx_dec
,
cipher_info
))
!=
0
)
{
SSL_DEBUG_RET
(
1
,
"cipher_init_ctx"
,
ret
);
return
(
ret
);
}
if
((
ret
=
cipher_setkey
(
&
transform
->
cipher_ctx_enc
,
key1
,
cipher_info
->
key_length
,
POLARSSL_ENCRYPT
))
!=
0
)
{
SSL_DEBUG_RET
(
1
,
"cipher_setkey"
,
ret
);
return
(
ret
);
}
if
((
ret
=
cipher_setkey
(
&
transform
->
cipher_ctx_dec
,
key2
,
cipher_info
->
key_length
,
POLARSSL_DECRYPT
))
!=
0
)
{
SSL_DEBUG_RET
(
1
,
"cipher_setkey"
,
ret
);
return
(
ret
);
}
if
(
cipher_info
->
mode
==
POLARSSL_MODE_CBC
)
{
if
((
ret
=
cipher_set_padding_mode
(
&
transform
->
cipher_ctx_enc
,
POLARSSL_PADDING_NONE
))
!=
0
)
{
SSL_DEBUG_RET
(
1
,
"cipher_set_padding_mode"
,
ret
);
return
(
ret
);
}
if
((
ret
=
cipher_set_padding_mode
(
&
transform
->
cipher_ctx_dec
,
POLARSSL_PADDING_NONE
))
!=
0
)
{
SSL_DEBUG_RET
(
1
,
"cipher_set_padding_mode"
,
ret
);
return
(
ret
);
}
}
wipememory
(
keyblk
,
sizeof
(
keyblk
));
/* Initialize compression. */
if
(
session
->
compression
==
SSL_COMPRESS_DEFLATE
)
{
if
(
ssl
->
compress_buf
==
NULL
)
{
debug_msg
(
3
,
"Allocating compression buffer"
);
ssl
->
compress_buf
=
malloc
(
SSL_BUFFER_LEN
);
if
(
!
ssl
->
compress_buf
)
{
err
=
gpg_error_from_syserror
();
debug_msg
(
1
,
"malloc(%d bytes) failed"
,
SSL_BUFFER_LEN
);
return
err
;
}
}
debug_msg
(
3
,
"Initializing zlib states"
);
memset
(
&
transform
->
ctx_deflate
,
0
,
sizeof
(
transform
->
ctx_deflate
));
memset
(
&
transform
->
ctx_inflate
,
0
,
sizeof
(
transform
->
ctx_inflate
));
if
(
deflateInit
(
&
transform
->
ctx_deflate
,
Z_DEFAULT_COMPRESSION
)
!=
Z_OK
||
inflateInit
(
&
transform
->
ctx_inflate
)
!=
Z_OK
)
{
debug_msg
(
1
,
"Failed to initialize compression"
);
return
(
POLARSSL_ERR_SSL_COMPRESSION_FAILED
);
}
}
debug_msg
(
2
,
"<= derive keys"
);
return
(
0
);
}
static
void
calc_verify_tls_sha256
(
ntbtls_t
ssl
,
unsigned
char
hash
[
32
])
{
sha256_context
sha256
;
debug_msg
(
2
,
"=> calc verify sha256"
);
memcpy
(
&
sha256
,
&
ssl
->
handshake
->
fin_sha256
,
sizeof
(
sha256_context
));
sha256_finish
(
&
sha256
,
hash
);
debug_buf
(
3
,
"calculated verify result"
,
hash
,
32
);
debug_msg
(
2
,
"<= calc verify"
);
sha256_free
(
&
sha256
);
return
;
}
static
void
calc_verify_tls_sha384
(
ntbtls_t
ssl
,
unsigned
char
hash
[
48
])
{
sha512_context
sha512
;
debug_msg
(
2
,
"=> calc verify sha384"
);
memcpy
(
&
sha512
,
&
ssl
->
handshake
->
fin_sha512
,
sizeof
(
sha512_context
));
sha512_finish
(
&
sha512
,
hash
);
debug_buf
(
3
,
"calculated verify result"
,
hash
,
48
);
debug_msg
(
2
,
"<= calc verify"
);
sha512_free
(
&
sha512
);
return
;
}
int
ssl_psk_derive_premaster
(
ntbtls_t
ssl
,
key_exchange_type_t
key_ex
)
{
unsigned
char
*
p
=
ssl
->
handshake
->
premaster
;
unsigned
char
*
end
=
p
+
sizeof
(
ssl
->
handshake
->
premaster
);
/*
* PMS = struct {
* opaque other_secret<0..2^16-1>;
* opaque psk<0..2^16-1>;
* };
* with "other_secret" depending on the particular key exchange
*/
if
(
key_ex
==
POLARSSL_KEY_EXCHANGE_PSK
)
{
if
(
end
-
p
<
2
+
(
int
)
ssl
->
psk_len
)
return
(
POLARSSL_ERR_SSL_BAD_INPUT_DATA
);
*
(
p
++
)
=
(
unsigned
char
)
(
ssl
->
psk_len
>>
8
);
*
(
p
++
)
=
(
unsigned
char
)
(
ssl
->
psk_len
);
p
+=
ssl
->
psk_len
;
}
else
if
(
key_ex
==
POLARSSL_KEY_EXCHANGE_RSA_PSK
)
{
/*
* other_secret already set by the ClientKeyExchange message,
* and is 48 bytes long
*/
*
p
++
=
0
;
*
p
++
=
48
;
p
+=
48
;
}
else
if
(
key_ex
==
POLARSSL_KEY_EXCHANGE_DHE_PSK
)
{
int
ret
;
size_t
len
=
end
-
(
p
+
2
);
/* Write length only when we know the actual value */
if
((
ret
=
dhm_calc_secret
(
&
ssl
->
handshake
->
dhm_ctx
,
p
+
2
,
&
len
,
ssl
->
f_rng
,
ssl
->
p_rng
))
!=
0
)
{
SSL_DEBUG_RET
(
1
,
"dhm_calc_secret"
,
ret
);
return
(
ret
);
}
*
(
p
++
)
=
(
unsigned
char
)
(
len
>>
8
);
*
(
p
++
)
=
(
unsigned
char
)
(
len
);
p
+=
len
;
SSL_DEBUG_MPI
(
3
,
"DHM: K "
,
&
ssl
->
handshake
->
dhm_ctx
.
K
);
}
else
if
(
key_ex
==
POLARSSL_KEY_EXCHANGE_ECDHE_PSK
)
{
int
ret
;
size_t
zlen
;
if
((
ret
=
ecdh_calc_secret
(
&
ssl
->
handshake
->
ecdh_ctx
,
&
zlen
,
p
+
2
,
end
-
(
p
+
2
),
ssl
->
f_rng
,
ssl
->
p_rng
))
!=
0
)
{
SSL_DEBUG_RET
(
1
,
"ecdh_calc_secret"
,
ret
);
return
(
ret
);
}
*
(
p
++
)
=
(
unsigned
char
)
(
zlen
>>
8
);
*
(
p
++
)
=
(
unsigned
char
)
(
zlen
);
p
+=
zlen
;
SSL_DEBUG_MPI
(
3
,
"ECDH: z"
,
&
ssl
->
handshake
->
ecdh_ctx
.
z
);
}
else
{
debug_bug
();
return
(
POLARSSL_ERR_SSL_INTERNAL_ERROR
);
}
/* opaque psk<0..2^16-1>; */
if
(
end
-
p
<
2
+
(
int
)
ssl
->
psk_len
)
return
(
POLARSSL_ERR_SSL_BAD_INPUT_DATA
);
*
(
p
++
)
=
(
unsigned
char
)
(
ssl
->
psk_len
>>
8
);
*
(
p
++
)
=
(
unsigned
char
)
(
ssl
->
psk_len
);
memcpy
(
p
,
ssl
->
psk
,
ssl
->
psk_len
);
p
+=
ssl
->
psk_len
;
ssl
->
handshake
->
pmslen
=
p
-
ssl
->
handshake
->
premaster
;
return
(
0
);
}
/*
* Encryption/decryption functions
*/
static
int
ssl_encrypt_buf
(
ntbtls_t
ssl
)
{
size_t
i
;
const
cipher_mode_t
mode
=
cipher_get_cipher_mode
(
&
ssl
->
transform_out
->
cipher_ctx_enc
);
debug_msg
(
2
,
"=> encrypt buf"
);
/*
* Add MAC before encrypt, except for AEAD modes
*/
if
(
mode
!=
POLARSSL_MODE_GCM
&&
mode
!=
POLARSSL_MODE_CCM
)
{
if
(
ssl
->
minor_ver
>=
SSL_MINOR_VERSION_1
)
{
md_hmac_update
(
&
ssl
->
transform_out
->
md_ctx_enc
,
ssl
->
out_ctr
,
13
);
md_hmac_update
(
&
ssl
->
transform_out
->
md_ctx_enc
,
ssl
->
out_msg
,
ssl
->
out_msglen
);
md_hmac_finish
(
&
ssl
->
transform_out
->
md_ctx_enc
,
ssl
->
out_msg
+
ssl
->
out_msglen
);
md_hmac_reset
(
&
ssl
->
transform_out
->
md_ctx_enc
);
}
else
{
debug_bug
();
return
(
POLARSSL_ERR_SSL_INTERNAL_ERROR
);
}
debug_buf
(
4
,
"computed mac"
,
ssl
->
out_msg
+
ssl
->
out_msglen
,
ssl
->
transform_out
->
maclen
);
ssl
->
out_msglen
+=
ssl
->
transform_out
->
maclen
;
}
/*
* Encrypt
*/
if
(
mode
==
POLARSSL_MODE_STREAM
)
{
int
ret
;
size_t
olen
=
0
;
debug_msg
(
3
,
"before encrypt: msglen = %d, "
"including %d bytes of padding"
,
ssl
->
out_msglen
,
0
);
debug_buf
(
4
,
"before encrypt: output payload"
,
ssl
->
out_msg
,
ssl
->
out_msglen
);
if
((
ret
=
cipher_crypt
(
&
ssl
->
transform_out
->
cipher_ctx_enc
,
ssl
->
transform_out
->
iv_enc
,
ssl
->
transform_out
->
ivlen
,
ssl
->
out_msg
,
ssl
->
out_msglen
,
ssl
->
out_msg
,
&
olen
))
!=
0
)
{
SSL_DEBUG_RET
(
1
,
"cipher_crypt"
,
ret
);
return
(
ret
);
}
if
(
ssl
->
out_msglen
!=
olen
)
{
debug_bug
();
return
(
POLARSSL_ERR_SSL_INTERNAL_ERROR
);
}
}
else
if
(
mode
==
POLARSSL_MODE_GCM
||
mode
==
POLARSSL_MODE_CCM
)
{
int
ret
;
size_t
enc_msglen
,
olen
;
unsigned
char
*
enc_msg
;
unsigned
char
add_data
[
13
];
unsigned
char
taglen
=
ssl
->
transform_out
->
ciphersuite_info
->
flags
&
POLARSSL_CIPHERSUITE_SHORT_TAG
?
8
:
16
;
memcpy
(
add_data
,
ssl
->
out_ctr
,
8
);
add_data
[
8
]
=
ssl
->
out_msgtype
;
add_data
[
9
]
=
ssl
->
major_ver
;
add_data
[
10
]
=
ssl
->
minor_ver
;
add_data
[
11
]
=
(
ssl
->
out_msglen
>>
8
)
&
0xFF
;
add_data
[
12
]
=
ssl
->
out_msglen
&
0xFF
;
debug_buf
(
4
,
"additional data used for AEAD"
,
add_data
,
13
);
/*
* Generate IV
*/
ret
=
ssl
->
f_rng
(
ssl
->
p_rng
,
ssl
->
transform_out
->
iv_enc
+
ssl
->
transform_out
->
fixed_ivlen
,
ssl
->
transform_out
->
ivlen
-
ssl
->
transform_out
->
fixed_ivlen
);
if
(
ret
!=
0
)
return
(
ret
);
memcpy
(
ssl
->
out_iv
,
ssl
->
transform_out
->
iv_enc
+
ssl
->
transform_out
->
fixed_ivlen
,
ssl
->
transform_out
->
ivlen
-
ssl
->
transform_out
->
fixed_ivlen
);
debug_buf
(
4
,
"IV used"
,
ssl
->
out_iv
,
ssl
->
transform_out
->
ivlen
-
ssl
->
transform_out
->
fixed_ivlen
);
/*
* Fix pointer positions and message length with added IV
*/
enc_msg
=
ssl
->
out_msg
;
enc_msglen
=
ssl
->
out_msglen
;
ssl
->
out_msglen
+=
ssl
->
transform_out
->
ivlen
-
ssl
->
transform_out
->
fixed_ivlen
;
debug_msg
(
3
,
"before encrypt: msglen = %d, "
"including %d bytes of padding"
,
ssl
->
out_msglen
,
0
);
debug_buf
(
4
,
"before encrypt: output payload"
,
ssl
->
out_msg
,
ssl
->
out_msglen
);
/*
* Encrypt and authenticate
*/
if
((
ret
=
cipher_auth_encrypt
(
&
ssl
->
transform_out
->
cipher_ctx_enc
,
ssl
->
transform_out
->
iv_enc
,
ssl
->
transform_out
->
ivlen
,
add_data
,
13
,
enc_msg
,
enc_msglen
,
enc_msg
,
&
olen
,
enc_msg
+
enc_msglen
,
taglen
))
!=
0
)
{
SSL_DEBUG_RET
(
1
,
"cipher_auth_encrypt"
,
ret
);
return
(
ret
);
}
if
(
olen
!=
enc_msglen
)
{
debug_bug
();
return
(
POLARSSL_ERR_SSL_INTERNAL_ERROR
);
}
ssl
->
out_msglen
+=
taglen
;
debug_buf
(
4
,
"after encrypt: tag"
,
enc_msg
+
enc_msglen
,
taglen
);
}
else
if
(
mode
==
POLARSSL_MODE_CBC
)
{
int
ret
;
unsigned
char
*
enc_msg
;
size_t
enc_msglen
,
padlen
,
olen
=
0
;
padlen
=
ssl
->
transform_out
->
ivlen
-
(
ssl
->
out_msglen
+
1
)
%
ssl
->
transform_out
->
ivlen
;
if
(
padlen
==
ssl
->
transform_out
->
ivlen
)
padlen
=
0
;
for
(
i
=
0
;
i
<=
padlen
;
i
++
)
ssl
->
out_msg
[
ssl
->
out_msglen
+
i
]
=
(
unsigned
char
)
padlen
;
ssl
->
out_msglen
+=
padlen
+
1
;
enc_msglen
=
ssl
->
out_msglen
;
enc_msg
=
ssl
->
out_msg
;
/*
* Prepend per-record IV for block cipher in TLS v1.1 and up as per
* Method 1 (6.2.3.2. in RFC4346 and RFC5246)
*/
if
(
ssl
->
minor_ver
>=
SSL_MINOR_VERSION_2
)
{
/*
* Generate IV
*/
int
ret
=
ssl
->
f_rng
(
ssl
->
p_rng
,
ssl
->
transform_out
->
iv_enc
,
ssl
->
transform_out
->
ivlen
);
if
(
ret
!=
0
)
return
(
ret
);
memcpy
(
ssl
->
out_iv
,
ssl
->
transform_out
->
iv_enc
,
ssl
->
transform_out
->
ivlen
);
/*
* Fix pointer positions and message length with added IV
*/
enc_msg
=
ssl
->
out_msg
;
enc_msglen
=
ssl
->
out_msglen
;
ssl
->
out_msglen
+=
ssl
->
transform_out
->
ivlen
;
}
debug_msg
(
3
,
"before encrypt: msglen = %d, "
"including %d bytes of IV and %d bytes of padding"
,
ssl
->
out_msglen
,
ssl
->
transform_out
->
ivlen
,
padlen
+
1
);
debug_buf
(
4
,
"before encrypt: output payload"
,
ssl
->
out_iv
,
ssl
->
out_msglen
);
if
((
ret
=
cipher_crypt
(
&
ssl
->
transform_out
->
cipher_ctx_enc
,
ssl
->
transform_out
->
iv_enc
,
ssl
->
transform_out
->
ivlen
,
enc_msg
,
enc_msglen
,
enc_msg
,
&
olen
))
!=
0
)
{
SSL_DEBUG_RET
(
1
,
"cipher_crypt"
,
ret
);
return
(
ret
);
}
if
(
enc_msglen
!=
olen
)
{
debug_bug
();
return
(
POLARSSL_ERR_SSL_INTERNAL_ERROR
);
}
}
else
{
debug_bug
();
return
(
POLARSSL_ERR_SSL_INTERNAL_ERROR
);
}
for
(
i
=
8
;
i
>
0
;
i
--
)
if
(
++
ssl
->
out_ctr
[
i
-
1
]
!=
0
)
break
;
/* The loops goes to its end iff the counter is wrapping */
if
(
i
==
0
)
{
debug_msg
(
1
,
"outgoing message counter would wrap"
);
return
(
POLARSSL_ERR_SSL_COUNTER_WRAPPING
);
}
debug_msg
(
2
,
"<= encrypt buf"
);
return
(
0
);
}
#define POLARSSL_SSL_MAX_MAC_SIZE 48
static
int
ssl_decrypt_buf
(
ntbtls_t
ssl
)
{
size_t
i
;
const
cipher_mode_t
mode
=
cipher_get_cipher_mode
(
&
ssl
->
transform_in
->
cipher_ctx_dec
);
size_t
padlen
=
0
,
correct
=
1
;
debug_msg
(
2
,
"=> decrypt buf"
);
if
(
ssl
->
in_msglen
<
ssl
->
transform_in
->
minlen
)
{
debug_msg
(
1
,
"in_msglen (%d) < minlen (%d)"
,
ssl
->
in_msglen
,
ssl
->
transform_in
->
minlen
);
return
(
POLARSSL_ERR_SSL_INVALID_MAC
);
}
if
(
mode
==
POLARSSL_MODE_STREAM
)
{
int
ret
;
size_t
olen
=
0
;
padlen
=
0
;
if
((
ret
=
cipher_crypt
(
&
ssl
->
transform_in
->
cipher_ctx_dec
,
ssl
->
transform_in
->
iv_dec
,
ssl
->
transform_in
->
ivlen
,
ssl
->
in_msg
,
ssl
->
in_msglen
,
ssl
->
in_msg
,
&
olen
))
!=
0
)
{
SSL_DEBUG_RET
(
1
,
"cipher_crypt"
,
ret
);
return
(
ret
);
}
if
(
ssl
->
in_msglen
!=
olen
)
{
debug_bug
();
return
(
POLARSSL_ERR_SSL_INTERNAL_ERROR
);
}
}
else
if
(
mode
==
POLARSSL_MODE_GCM
||
mode
==
POLARSSL_MODE_CCM
)
{
int
ret
;
size_t
dec_msglen
,
olen
;
unsigned
char
*
dec_msg
;
unsigned
char
*
dec_msg_result
;
unsigned
char
add_data
[
13
];
unsigned
char
taglen
=
ssl
->
transform_in
->
ciphersuite_info
->
flags
&
POLARSSL_CIPHERSUITE_SHORT_TAG
?
8
:
16
;
unsigned
char
explicit_iv_len
=
ssl
->
transform_in
->
ivlen
-
ssl
->
transform_in
->
fixed_ivlen
;
if
(
ssl
->
in_msglen
<
explicit_iv_len
+
taglen
)
{
debug_msg
(
1
,
"msglen (%d) < explicit_iv_len (%d) "
"+ taglen (%d)"
,
ssl
->
in_msglen
,
explicit_iv_len
,
taglen
);
return
(
POLARSSL_ERR_SSL_INVALID_MAC
);
}
dec_msglen
=
ssl
->
in_msglen
-
explicit_iv_len
-
taglen
;
dec_msg
=
ssl
->
in_msg
;
dec_msg_result
=
ssl
->
in_msg
;
ssl
->
in_msglen
=
dec_msglen
;
memcpy
(
add_data
,
ssl
->
in_ctr
,
8
);
add_data
[
8
]
=
ssl
->
in_msgtype
;
add_data
[
9
]
=
ssl
->
major_ver
;
add_data
[
10
]
=
ssl
->
minor_ver
;
add_data
[
11
]
=
(
ssl
->
in_msglen
>>
8
)
&
0xFF
;
add_data
[
12
]
=
ssl
->
in_msglen
&
0xFF
;
debug_buf
(
4
,
"additional data used for AEAD"
,
add_data
,
13
);
memcpy
(
ssl
->
transform_in
->
iv_dec
+
ssl
->
transform_in
->
fixed_ivlen
,
ssl
->
in_iv
,
ssl
->
transform_in
->
ivlen
-
ssl
->
transform_in
->
fixed_ivlen
);
debug_buf
(
4
,
"IV used"
,
ssl
->
transform_in
->
iv_dec
,
ssl
->
transform_in
->
ivlen
);
debug_buf
(
4
,
"TAG used"
,
dec_msg
+
dec_msglen
,
taglen
);
/*
* Decrypt and authenticate
*/
if
((
ret
=
cipher_auth_decrypt
(
&
ssl
->
transform_in
->
cipher_ctx_dec
,
ssl
->
transform_in
->
iv_dec
,
ssl
->
transform_in
->
ivlen
,
add_data
,
13
,
dec_msg
,
dec_msglen
,
dec_msg_result
,
&
olen
,
dec_msg
+
dec_msglen
,
taglen
))
!=
0
)
{
SSL_DEBUG_RET
(
1
,
"cipher_auth_decrypt"
,
ret
);
if
(
ret
==
POLARSSL_ERR_CIPHER_AUTH_FAILED
)
return
(
POLARSSL_ERR_SSL_INVALID_MAC
);
return
(
ret
);
}
if
(
olen
!=
dec_msglen
)
{
debug_bug
();
return
(
POLARSSL_ERR_SSL_INTERNAL_ERROR
);
}
}
else
if
(
mode
==
POLARSSL_MODE_CBC
)
{
/*
* Decrypt and check the padding
*/
int
ret
;
unsigned
char
*
dec_msg
;
unsigned
char
*
dec_msg_result
;
size_t
dec_msglen
;
size_t
minlen
=
0
;
size_t
olen
=
0
;
/*
* Check immediate ciphertext sanity
*/
if
(
ssl
->
in_msglen
%
ssl
->
transform_in
->
ivlen
!=
0
)
{
debug_msg
(
1
,
"msglen (%d) %% ivlen (%d) != 0"
,
ssl
->
in_msglen
,
ssl
->
transform_in
->
ivlen
);
return
(
POLARSSL_ERR_SSL_INVALID_MAC
);
}
if
(
ssl
->
minor_ver
>=
SSL_MINOR_VERSION_2
)
minlen
+=
ssl
->
transform_in
->
ivlen
;
if
(
ssl
->
in_msglen
<
minlen
+
ssl
->
transform_in
->
ivlen
||
ssl
->
in_msglen
<
minlen
+
ssl
->
transform_in
->
maclen
+
1
)
{
debug_msg
(
1
,
"msglen (%d) < max( ivlen(%d), maclen (%d) "
"+ 1 ) ( + expl IV )"
,
ssl
->
in_msglen
,
ssl
->
transform_in
->
ivlen
,
ssl
->
transform_in
->
maclen
);
return
(
POLARSSL_ERR_SSL_INVALID_MAC
);
}
dec_msglen
=
ssl
->
in_msglen
;
dec_msg
=
ssl
->
in_msg
;
dec_msg_result
=
ssl
->
in_msg
;
/*
* Initialize for prepended IV for block cipher in TLS v1.1 and up
*/
if
(
ssl
->
minor_ver
>=
SSL_MINOR_VERSION_2
)
{
dec_msglen
-=
ssl
->
transform_in
->
ivlen
;
ssl
->
in_msglen
-=
ssl
->
transform_in
->
ivlen
;
for
(
i
=
0
;
i
<
ssl
->
transform_in
->
ivlen
;
i
++
)
ssl
->
transform_in
->
iv_dec
[
i
]
=
ssl
->
in_iv
[
i
];
}
if
((
ret
=
cipher_crypt
(
&
ssl
->
transform_in
->
cipher_ctx_dec
,
ssl
->
transform_in
->
iv_dec
,
ssl
->
transform_in
->
ivlen
,
dec_msg
,
dec_msglen
,
dec_msg_result
,
&
olen
))
!=
0
)
{
SSL_DEBUG_RET
(
1
,
"cipher_crypt"
,
ret
);
return
(
ret
);
}
if
(
dec_msglen
!=
olen
)
{
debug_bug
();
return
(
POLARSSL_ERR_SSL_INTERNAL_ERROR
);
}
padlen
=
1
+
ssl
->
in_msg
[
ssl
->
in_msglen
-
1
];
if
(
ssl
->
in_msglen
<
ssl
->
transform_in
->
maclen
+
padlen
)
{
debug_msg
(
1
,
"msglen (%d) < maclen (%d) + padlen (%d)"
,
ssl
->
in_msglen
,
ssl
->
transform_in
->
maclen
,
padlen
);
padlen
=
0
;
correct
=
0
;
}
if
(
ssl
->
minor_ver
>
SSL_MINOR_VERSION_0
)
{
/*
* TLSv1+: always check the padding up to the first failure
* and fake check up to 256 bytes of padding
*/
size_t
pad_count
=
0
,
real_count
=
1
;
size_t
padding_idx
=
ssl
->
in_msglen
-
padlen
-
1
;
/*
* Padding is guaranteed to be incorrect if:
* 1. padlen >= ssl->in_msglen
*
* 2. padding_idx >= SSL_MAX_CONTENT_LEN +
* ssl->transform_in->maclen
*
* In both cases we reset padding_idx to a safe value (0) to
* prevent out-of-buffer reads.
*/
correct
&=
(
ssl
->
in_msglen
>=
padlen
+
1
);
correct
&=
(
padding_idx
<
SSL_MAX_CONTENT_LEN
+
ssl
->
transform_in
->
maclen
);
padding_idx
*=
correct
;
for
(
i
=
1
;
i
<=
256
;
i
++
)
{
real_count
&=
(
i
<=
padlen
);
pad_count
+=
real_count
*
(
ssl
->
in_msg
[
padding_idx
+
i
]
==
padlen
-
1
);
}
correct
&=
(
pad_count
==
padlen
);
/* Only 1 on correct padding */
if
(
padlen
>
0
&&
correct
==
0
)
debug_msg
(
1
,
"bad padding byte detected"
);
padlen
&=
correct
*
0x1FF
;
}
else
{
debug_bug
();
return
(
POLARSSL_ERR_SSL_INTERNAL_ERROR
);
}
}
else
{
debug_bug
();
return
(
POLARSSL_ERR_SSL_INTERNAL_ERROR
);
}
debug_buf
(
4
,
"raw buffer after decryption"
,
ssl
->
in_msg
,
ssl
->
in_msglen
);
/*
* Always compute the MAC (RFC4346, CBCTIME), except for AEAD of course
*/
if
(
mode
!=
POLARSSL_MODE_GCM
&&
mode
!=
POLARSSL_MODE_CCM
)
{
unsigned
char
tmp
[
POLARSSL_SSL_MAX_MAC_SIZE
];
ssl
->
in_msglen
-=
(
ssl
->
transform_in
->
maclen
+
padlen
);
ssl
->
in_hdr
[
3
]
=
(
unsigned
char
)
(
ssl
->
in_msglen
>>
8
);
ssl
->
in_hdr
[
4
]
=
(
unsigned
char
)
(
ssl
->
in_msglen
);
memcpy
(
tmp
,
ssl
->
in_msg
+
ssl
->
in_msglen
,
ssl
->
transform_in
->
maclen
);
if
(
ssl
->
minor_ver
>
SSL_MINOR_VERSION_0
)
{
/*
* Process MAC and always update for padlen afterwards to make
* total time independent of padlen
*
* extra_run compensates MAC check for padlen
*
* Known timing attacks:
* - Lucky Thirteen (http://www.isg.rhul.ac.uk/tls/TLStiming.pdf)
*
* We use ( ( Lx + 8 ) / 64 ) to handle 'negative Lx' values
* correctly. (We round down instead of up, so -56 is the correct
* value for our calculations instead of -55)
*/
size_t
j
,
extra_run
=
0
;
extra_run
=
(
13
+
ssl
->
in_msglen
+
padlen
+
8
)
/
64
-
(
13
+
ssl
->
in_msglen
+
8
)
/
64
;
extra_run
&=
correct
*
0xFF
;
md_hmac_update
(
&
ssl
->
transform_in
->
md_ctx_dec
,
ssl
->
in_ctr
,
13
);
md_hmac_update
(
&
ssl
->
transform_in
->
md_ctx_dec
,
ssl
->
in_msg
,
ssl
->
in_msglen
);
md_hmac_finish
(
&
ssl
->
transform_in
->
md_ctx_dec
,
ssl
->
in_msg
+
ssl
->
in_msglen
);
for
(
j
=
0
;
j
<
extra_run
;
j
++
)
md_process
(
&
ssl
->
transform_in
->
md_ctx_dec
,
ssl
->
in_msg
);
md_hmac_reset
(
&
ssl
->
transform_in
->
md_ctx_dec
);
}
else
{
debug_bug
();
return
(
POLARSSL_ERR_SSL_INTERNAL_ERROR
);
}
debug_buf
(
4
,
"message mac"
,
tmp
,
ssl
->
transform_in
->
maclen
);
debug_buf
(
4
,
"computed mac"
,
ssl
->
in_msg
+
ssl
->
in_msglen
,
ssl
->
transform_in
->
maclen
);
if
(
safer_memcmp
(
tmp
,
ssl
->
in_msg
+
ssl
->
in_msglen
,
ssl
->
transform_in
->
maclen
)
!=
0
)
{
debug_msg
(
1
,
"message mac does not match"
);
correct
=
0
;
}
/*
* Finally check the correct flag
*/
if
(
correct
==
0
)
return
(
POLARSSL_ERR_SSL_INVALID_MAC
);
}
if
(
ssl
->
in_msglen
==
0
)
{
ssl
->
nb_zero
++
;
/*
* Three or more empty messages may be a DoS attack
* (excessive CPU consumption).
*/
if
(
ssl
->
nb_zero
>
3
)
{
debug_msg
(
1
,
"received four consecutive empty "
"messages, possible DoS attack"
);
return
(
POLARSSL_ERR_SSL_INVALID_MAC
);
}
}
else
ssl
->
nb_zero
=
0
;
for
(
i
=
8
;
i
>
0
;
i
--
)
if
(
++
ssl
->
in_ctr
[
i
-
1
]
!=
0
)
break
;
/* The loops goes to its end iff the counter is wrapping */
if
(
i
==
0
)
{
debug_msg
(
1
,
"incoming message counter would wrap"
);
return
(
POLARSSL_ERR_SSL_COUNTER_WRAPPING
);
}
debug_msg
(
2
,
"<= decrypt buf"
);
return
(
0
);
}
/*
* Compression/decompression functions
*/
static
int
ssl_compress_buf
(
ntbtls_t
ssl
)
{
int
ret
;
unsigned
char
*
msg_post
=
ssl
->
out_msg
;
size_t
len_pre
=
ssl
->
out_msglen
;
unsigned
char
*
msg_pre
=
ssl
->
compress_buf
;
debug_msg
(
2
,
"=> compress buf"
);
if
(
len_pre
==
0
)
return
(
0
);
memcpy
(
msg_pre
,
ssl
->
out_msg
,
len_pre
);
debug_msg
(
3
,
"before compression: msglen = %d, "
,
ssl
->
out_msglen
);
debug_buf
(
4
,
"before compression: output payload"
,
ssl
->
out_msg
,
ssl
->
out_msglen
);
ssl
->
transform_out
->
ctx_deflate
.
next_in
=
msg_pre
;
ssl
->
transform_out
->
ctx_deflate
.
avail_in
=
len_pre
;
ssl
->
transform_out
->
ctx_deflate
.
next_out
=
msg_post
;
ssl
->
transform_out
->
ctx_deflate
.
avail_out
=
SSL_BUFFER_LEN
;
ret
=
deflate
(
&
ssl
->
transform_out
->
ctx_deflate
,
Z_SYNC_FLUSH
);
if
(
ret
!=
Z_OK
)
{
debug_msg
(
1
,
"failed to perform compression (%d)"
,
ret
);
return
(
POLARSSL_ERR_SSL_COMPRESSION_FAILED
);
}
ssl
->
out_msglen
=
SSL_BUFFER_LEN
-
ssl
->
transform_out
->
ctx_deflate
.
avail_out
;
debug_msg
(
3
,
"after compression: msglen = %d, "
,
ssl
->
out_msglen
);
debug_buf
(
4
,
"after compression: output payload"
,
ssl
->
out_msg
,
ssl
->
out_msglen
);
debug_msg
(
2
,
"<= compress buf"
);
return
(
0
);
}
static
int
ssl_decompress_buf
(
ntbtls_t
ssl
)
{
int
ret
;
unsigned
char
*
msg_post
=
ssl
->
in_msg
;
size_t
len_pre
=
ssl
->
in_msglen
;
unsigned
char
*
msg_pre
=
ssl
->
compress_buf
;
debug_msg
(
2
,
"=> decompress buf"
);
if
(
len_pre
==
0
)
return
(
0
);
memcpy
(
msg_pre
,
ssl
->
in_msg
,
len_pre
);
debug_msg
(
3
,
"before decompression: msglen = %d, "
,
ssl
->
in_msglen
);
debug_buf
(
4
,
"before decompression: input payload"
,
ssl
->
in_msg
,
ssl
->
in_msglen
);
ssl
->
transform_in
->
ctx_inflate
.
next_in
=
msg_pre
;
ssl
->
transform_in
->
ctx_inflate
.
avail_in
=
len_pre
;
ssl
->
transform_in
->
ctx_inflate
.
next_out
=
msg_post
;
ssl
->
transform_in
->
ctx_inflate
.
avail_out
=
SSL_MAX_CONTENT_LEN
;
ret
=
inflate
(
&
ssl
->
transform_in
->
ctx_inflate
,
Z_SYNC_FLUSH
);
if
(
ret
!=
Z_OK
)
{
debug_msg
(
1
,
"failed to perform decompression (%d)"
,
ret
);
return
(
POLARSSL_ERR_SSL_COMPRESSION_FAILED
);
}
ssl
->
in_msglen
=
SSL_MAX_CONTENT_LEN
-
ssl
->
transform_in
->
ctx_inflate
.
avail_out
;
debug_msg
(
3
,
"after decompression: msglen = %d, "
,
ssl
->
in_msglen
);
debug_buf
(
4
,
"after decompression: input payload"
,
ssl
->
in_msg
,
ssl
->
in_msglen
);
debug_msg
(
2
,
"<= decompress buf"
);
return
(
0
);
}
/* Fill the input message buffer with NB_WANT bytes. The function
* returns an error if the numer of requested bytes do not fit into
* the record buffer, there is a read problem, or on EOF. */
gpg_error_t
_ntbtls_fetch_input
(
ntbtls_t
tls
,
size_t
nb_want
)
{
gpg_error_t
err
;
size_t
len
,
nread
;
debug_msg
(
2
,
"=> fetch input"
);
if
(
!
tls
->
inbound
)
return
gpg_error
(
GPG_ERR_NOT_INITIALIZED
);
if
(
nb_want
>
TLS_BUFFER_LEN
-
8
)
{
debug_msg
(
1
,
"requesting more data than fits"
);
// FiXME; New code for "request too long for buffer"?
return
gpg_error
(
GPG_ERR_BUFFER_TOO_SHORT
);
}
err
=
0
;
while
(
tls
->
in_left
<
nb_want
)
{
len
=
nb_want
-
ssl
->
in_left
;
if
(
es_read
(
tls
->
inbound
,
ssl
->
in_hdr
+
ssl
->
in_left
,
len
,
&
nread
))
err
=
gpg_error_from_syserror
();
debug_msg
(
2
,
"in_left: %d, nb_want: %d"
,
ssl
->
in_left
,
nb_want
);
SSL_DEBUG_RET
(
2
,
"ssl->f_recv"
,
nread
);
if
(
err
||
!
nread
/*ie. EOF*/
)
break
;
ssl
->
in_left
+=
nread
;
}
debug_msg
(
2
,
"<= fetch input"
);
return
0
;
}
/*
* Flush any data not yet written
*/
gpg_error_t
_ntbtls_flush_output
(
ntbtls_t
tls
)
{
gpg_error_t
err
;
unsigned
char
*
buf
;
size_t
nwritten
;
debug_msg
(
2
,
"=> flush output"
);
if
(
!
tls
->
outbound
)
return
gpg_error
(
GPG_ERR_NOT_INITIALIZED
);
err
=
0
;
while
(
tls
->
out_left
>
0
)
{
debug_msg
(
2
,
"message length: %d, out_left: %d"
,
5
+
ssl
->
out_msglen
,
ssl
->
out_left
);
buf
=
tls
->
out_hdr
+
5
+
tls
->
out_msglen
-
tls
->
out_left
;
if
(
es_write
(
tls
->
outbound
,
buf
,
ssl
->
out_left
,
nwritten
))
err
=
gpg_error_from_syserror
();
SSL_DEBUG_RET
(
2
,
"ssl->f_send"
,
err
);
if
(
err
)
break
;
ssl
->
out_left
-=
nwritten
;
}
debug_msg
(
2
,
"<= flush output"
);
return
err
;
}
/*
* Record layer functions
*/
int
_ntbtls_write_record
(
ntbtls_t
ssl
)
{
int
ret
,
done
=
0
;
size_t
len
=
ssl
->
out_msglen
;
debug_msg
(
2
,
"=> write record"
);
if
(
ssl
->
out_msgtype
==
TLS_MSG_HANDSHAKE
)
{
ssl
->
out_msg
[
1
]
=
(
unsigned
char
)
((
len
-
4
)
>>
16
);
ssl
->
out_msg
[
2
]
=
(
unsigned
char
)
((
len
-
4
)
>>
8
);
ssl
->
out_msg
[
3
]
=
(
unsigned
char
)
((
len
-
4
));
if
(
ssl
->
out_msg
[
0
]
!=
TLS_HS_HELLO_REQUEST
)
ssl
->
handshake
->
update_checksum
(
ssl
,
ssl
->
out_msg
,
len
);
}
if
(
ssl
->
transform_out
!=
NULL
&&
ssl
->
session_out
->
compression
==
SSL_COMPRESS_DEFLATE
)
{
if
((
ret
=
ssl_compress_buf
(
ssl
))
!=
0
)
{
SSL_DEBUG_RET
(
1
,
"ssl_compress_buf"
,
ret
);
return
(
ret
);
}
len
=
ssl
->
out_msglen
;
}
if
(
!
done
)
{
ssl
->
out_hdr
[
0
]
=
(
unsigned
char
)
ssl
->
out_msgtype
;
ssl
->
out_hdr
[
1
]
=
(
unsigned
char
)
ssl
->
major_ver
;
ssl
->
out_hdr
[
2
]
=
(
unsigned
char
)
ssl
->
minor_ver
;
ssl
->
out_hdr
[
3
]
=
(
unsigned
char
)
(
len
>>
8
);
ssl
->
out_hdr
[
4
]
=
(
unsigned
char
)
(
len
);
if
(
ssl
->
transform_out
!=
NULL
)
{
if
((
ret
=
ssl_encrypt_buf
(
ssl
))
!=
0
)
{
SSL_DEBUG_RET
(
1
,
"ssl_encrypt_buf"
,
ret
);
return
(
ret
);
}
len
=
ssl
->
out_msglen
;
ssl
->
out_hdr
[
3
]
=
(
unsigned
char
)
(
len
>>
8
);
ssl
->
out_hdr
[
4
]
=
(
unsigned
char
)
(
len
);
}
ssl
->
out_left
=
5
+
ssl
->
out_msglen
;
debug_msg
(
3
,
"output record: msgtype = %d, "
"version = [%d:%d], msglen = %d"
,
ssl
->
out_hdr
[
0
],
ssl
->
out_hdr
[
1
],
ssl
->
out_hdr
[
2
],
(
ssl
->
out_hdr
[
3
]
<<
8
)
|
ssl
->
out_hdr
[
4
]);
debug_buf
(
4
,
"output record sent to network"
,
ssl
->
out_hdr
,
5
+
ssl
->
out_msglen
);
}
err
=
_ntbtls_flush_output
(
tls
);
if
(
err
)
{
SSL_DEBUG_RET
(
1
,
"ssl_flush_output"
,
err
);
return
ret
;
}
debug_msg
(
2
,
"<= write record"
);
return
(
0
);
}
int
ssl_read_record
(
ntbtls_t
ssl
)
{
int
ret
,
done
=
0
;
debug_msg
(
2
,
"=> read record"
);
if
(
ssl
->
in_hslen
!=
0
&&
ssl
->
in_hslen
<
ssl
->
in_msglen
)
{
/*
* Get next Handshake message in the current record
*/
ssl
->
in_msglen
-=
ssl
->
in_hslen
;
memmove
(
ssl
->
in_msg
,
ssl
->
in_msg
+
ssl
->
in_hslen
,
ssl
->
in_msglen
);
ssl
->
in_hslen
=
4
;
ssl
->
in_hslen
+=
(
ssl
->
in_msg
[
2
]
<<
8
)
|
ssl
->
in_msg
[
3
];
debug_msg
(
3
,
"handshake message: msglen ="
" %d, type = %d, hslen = %d"
,
ssl
->
in_msglen
,
ssl
->
in_msg
[
0
],
ssl
->
in_hslen
);
if
(
ssl
->
in_msglen
<
4
||
ssl
->
in_msg
[
1
]
!=
0
)
{
debug_msg
(
1
,
"bad handshake length"
);
return
(
POLARSSL_ERR_SSL_INVALID_RECORD
);
}
if
(
ssl
->
in_msglen
<
ssl
->
in_hslen
)
{
debug_msg
(
1
,
"bad handshake length"
);
return
(
POLARSSL_ERR_SSL_INVALID_RECORD
);
}
if
(
ssl
->
state
!=
SSL_HANDSHAKE_OVER
)
ssl
->
handshake
->
update_checksum
(
ssl
,
ssl
->
in_msg
,
ssl
->
in_hslen
);
return
(
0
);
}
ssl
->
in_hslen
=
0
;
/*
* Read the record header and validate it
*/
err
=
_ntbtls_fetch_input
(
ssl
,
5
);
if
(
err
)
{
SSL_DEBUG_RET
(
1
,
"ssl_fetch_input"
,
err
);
return
err
;
}
//FIXME: Handle EOF
ssl
->
in_msgtype
=
ssl
->
in_hdr
[
0
];
ssl
->
in_msglen
=
(
ssl
->
in_hdr
[
3
]
<<
8
)
|
ssl
->
in_hdr
[
4
];
debug_msg
(
3
,
"input record: msgtype = %d, "
"version = [%d:%d], msglen = %d"
,
ssl
->
in_hdr
[
0
],
ssl
->
in_hdr
[
1
],
ssl
->
in_hdr
[
2
],
(
ssl
->
in_hdr
[
3
]
<<
8
)
|
ssl
->
in_hdr
[
4
]);
if
(
ssl
->
in_hdr
[
1
]
!=
ssl
->
major_ver
)
{
debug_msg
(
1
,
"major version mismatch"
);
return
(
POLARSSL_ERR_SSL_INVALID_RECORD
);
}
if
(
ssl
->
in_hdr
[
2
]
>
ssl
->
max_minor_ver
)
{
debug_msg
(
1
,
"minor version mismatch"
);
return
(
POLARSSL_ERR_SSL_INVALID_RECORD
);
}
/* Sanity check (outer boundaries) */
if
(
ssl
->
in_msglen
<
1
||
ssl
->
in_msglen
>
SSL_BUFFER_LEN
-
13
)
{
debug_msg
(
1
,
"bad message length"
);
return
(
POLARSSL_ERR_SSL_INVALID_RECORD
);
}
/*
* Make sure the message length is acceptable for the current transform
* and protocol version.
*/
if
(
ssl
->
transform_in
==
NULL
)
{
if
(
ssl
->
in_msglen
>
SSL_MAX_CONTENT_LEN
)
{
debug_msg
(
1
,
"bad message length"
);
return
(
POLARSSL_ERR_SSL_INVALID_RECORD
);
}
}
else
{
if
(
ssl
->
in_msglen
<
ssl
->
transform_in
->
minlen
)
{
debug_msg
(
1
,
"bad message length"
);
return
(
POLARSSL_ERR_SSL_INVALID_RECORD
);
}
/*
* TLS encrypted messages can have up to 256 bytes of padding
*/
if
(
ssl
->
minor_ver
>=
SSL_MINOR_VERSION_1
&&
ssl
->
in_msglen
>
ssl
->
transform_in
->
minlen
+
SSL_MAX_CONTENT_LEN
+
256
)
{
debug_msg
(
1
,
"bad message length"
);
return
(
POLARSSL_ERR_SSL_INVALID_RECORD
);
}
}
/*
* Read and optionally decrypt the message contents
*/
err
=
_ntbtls_fetch_input
(
ssl
,
5
+
ssl
->
in_msglen
);
if
(
err
)
{
SSL_DEBUG_RET
(
1
,
"ssl_fetch_input"
,
err
);
return
err
;
}
//FIXME: Handle EOF
debug_buf
(
4
,
"input record from network"
,
ssl
->
in_hdr
,
5
+
ssl
->
in_msglen
);
if
(
!
done
&&
ssl
->
transform_in
!=
NULL
)
{
if
((
ret
=
ssl_decrypt_buf
(
ssl
))
!=
0
)
{
if
(
ret
==
POLARSSL_ERR_SSL_INVALID_MAC
)
{
ssl_send_alert_message
(
ssl
,
TLS_ALERT_LEVEL_FATAL
,
TLS_ALERT_MSG_BAD_RECORD_MAC
);
}
SSL_DEBUG_RET
(
1
,
"ssl_decrypt_buf"
,
ret
);
return
(
ret
);
}
debug_buf
(
4
,
"input payload after decrypt"
,
ssl
->
in_msg
,
ssl
->
in_msglen
);
if
(
ssl
->
in_msglen
>
SSL_MAX_CONTENT_LEN
)
{
debug_msg
(
1
,
"bad message length"
);
return
(
POLARSSL_ERR_SSL_INVALID_RECORD
);
}
}
if
(
ssl
->
transform_in
!=
NULL
&&
ssl
->
session_in
->
compression
==
SSL_COMPRESS_DEFLATE
)
{
if
((
ret
=
ssl_decompress_buf
(
ssl
))
!=
0
)
{
SSL_DEBUG_RET
(
1
,
"ssl_decompress_buf"
,
ret
);
return
(
ret
);
}
ssl
->
in_hdr
[
3
]
=
(
unsigned
char
)
(
ssl
->
in_msglen
>>
8
);
ssl
->
in_hdr
[
4
]
=
(
unsigned
char
)
(
ssl
->
in_msglen
);
}
if
(
ssl
->
in_msgtype
!=
TLS_MSG_HANDSHAKE
&&
ssl
->
in_msgtype
!=
TLS_MSG_ALERT
&&
ssl
->
in_msgtype
!=
TLS_MSG_CHANGE_CIPHER_SPEC
&&
ssl
->
in_msgtype
!=
TLS_MSG_APPLICATION_DATA
)
{
debug_msg
(
1
,
"unknown record type"
);
if
((
ret
=
ssl_send_alert_message
(
ssl
,
TLS_ALERT_LEVEL_FATAL
,
TLS_ALERT_MSG_UNEXPECTED_MESSAGE
))
!=
0
)
{
return
(
ret
);
}
return
(
POLARSSL_ERR_SSL_INVALID_RECORD
);
}
if
(
ssl
->
in_msgtype
==
TLS_MSG_HANDSHAKE
)
{
ssl
->
in_hslen
=
4
;
ssl
->
in_hslen
+=
(
ssl
->
in_msg
[
2
]
<<
8
)
|
ssl
->
in_msg
[
3
];
debug_msg
(
3
,
"handshake message: msglen ="
" %d, type = %d, hslen = %d"
,
ssl
->
in_msglen
,
ssl
->
in_msg
[
0
],
ssl
->
in_hslen
);
/*
* Additional checks to validate the handshake header
*/
if
(
ssl
->
in_msglen
<
4
||
ssl
->
in_msg
[
1
]
!=
0
)
{
debug_msg
(
1
,
"bad handshake length"
);
return
(
POLARSSL_ERR_SSL_INVALID_RECORD
);
}
if
(
ssl
->
in_msglen
<
ssl
->
in_hslen
)
{
debug_msg
(
1
,
"bad handshake length"
);
return
(
POLARSSL_ERR_SSL_INVALID_RECORD
);
}
if
(
ssl
->
state
!=
SSL_HANDSHAKE_OVER
)
ssl
->
handshake
->
update_checksum
(
ssl
,
ssl
->
in_msg
,
ssl
->
in_hslen
);
}
if
(
ssl
->
in_msgtype
==
TLS_MSG_ALERT
)
{
debug_msg
(
2
,
"got an alert message, type: [%d:%d]"
,
ssl
->
in_msg
[
0
],
ssl
->
in_msg
[
1
]);
/*
* Ignore non-fatal alerts, except close_notify
*/
if
(
ssl
->
in_msg
[
0
]
==
TLS_ALERT_LEVEL_FATAL
)
{
debug_msg
(
1
,
"is a fatal alert message (msg %d)"
,
ssl
->
in_msg
[
1
]);
/**
* Subtract from error code as ssl->in_msg[1] is 7-bit positive
* error identifier.
*/
return
(
POLARSSL_ERR_SSL_FATAL_ALERT_MESSAGE
);
}
if
(
ssl
->
in_msg
[
0
]
==
TLS_ALERT_LEVEL_WARNING
&&
ssl
->
in_msg
[
1
]
==
TLS_ALERT_MSG_CLOSE_NOTIFY
)
{
debug_msg
(
2
,
"is a close notify message"
);
return
(
POLARSSL_ERR_SSL_PEER_CLOSE_NOTIFY
);
}
}
ssl
->
in_left
=
0
;
debug_msg
(
2
,
"<= read record"
);
return
(
0
);
}
int
ssl_send_fatal_handshake_failure
(
ntbtls_t
ssl
)
{
int
ret
;
if
((
ret
=
ssl_send_alert_message
(
ssl
,
TLS_ALERT_LEVEL_FATAL
,
TLS_ALERT_MSG_HANDSHAKE_FAILURE
))
!=
0
)
{
return
(
ret
);
}
return
(
0
);
}
int
ssl_send_alert_message
(
ntbtls_t
ssl
,
unsigned
char
level
,
unsigned
char
message
)
{
int
ret
;
debug_msg
(
2
,
"=> send alert message"
);
ssl
->
out_msgtype
=
TLS_MSG_ALERT
;
ssl
->
out_msglen
=
2
;
ssl
->
out_msg
[
0
]
=
level
;
ssl
->
out_msg
[
1
]
=
message
;
if
((
ret
=
ssl_write_record
(
ssl
))
!=
0
)
{
SSL_DEBUG_RET
(
1
,
"ssl_write_record"
,
ret
);
return
(
ret
);
}
debug_msg
(
2
,
"<= send alert message"
);
return
(
0
);
}
/*
* Handshake functions
*/
int
_ntbtls_write_certificate
(
ntbtls_t
ssl
)
{
int
ret
=
POLARSSL_ERR_SSL_FEATURE_UNAVAILABLE
;
size_t
i
,
n
;
const
x509_crt
*
crt
;
const
ssl_ciphersuite_t
*
ciphersuite_info
=
ssl
->
transform_negotiate
->
ciphersuite_info
;
debug_msg
(
2
,
"=> write certificate"
);
if
(
ciphersuite_info
->
key_exchange
==
POLARSSL_KEY_EXCHANGE_PSK
||
ciphersuite_info
->
key_exchange
==
POLARSSL_KEY_EXCHANGE_DHE_PSK
||
ciphersuite_info
->
key_exchange
==
POLARSSL_KEY_EXCHANGE_ECDHE_PSK
)
{
debug_msg
(
2
,
"<= skip write certificate"
);
ssl
->
state
++
;
return
(
0
);
}
if
(
ssl
->
is_client
)
{
if
(
ssl
->
client_auth
==
0
)
{
debug_msg
(
2
,
"<= skip write certificate"
);
ssl
->
state
++
;
return
(
0
);
}
}
else
/* SSL_IS_SERVER */
{
if
(
ssl_own_cert
(
ssl
)
==
NULL
)
{
debug_msg
(
1
,
"got no certificate to send"
);
return
(
POLARSSL_ERR_SSL_CERTIFICATE_REQUIRED
);
}
}
SSL_DEBUG_CRT
(
3
,
"own certificate"
,
ssl_own_cert
(
ssl
));
/*
* 0 . 0 handshake type
* 1 . 3 handshake length
* 4 . 6 length of all certs
* 7 . 9 length of cert. 1
* 10 . n-1 peer certificate
* n . n+2 length of cert. 2
* n+3 . ... upper level cert, etc.
*/
i
=
7
;
crt
=
ssl_own_cert
(
ssl
);
while
(
crt
!=
NULL
)
{
n
=
crt
->
raw
.
len
;
if
(
n
>
SSL_MAX_CONTENT_LEN
-
3
-
i
)
{
debug_msg
(
1
,
"certificate too large, %d > %d"
,
i
+
3
+
n
,
SSL_MAX_CONTENT_LEN
);
return
(
POLARSSL_ERR_SSL_CERTIFICATE_TOO_LARGE
);
}
ssl
->
out_msg
[
i
]
=
(
unsigned
char
)
(
n
>>
16
);
ssl
->
out_msg
[
i
+
1
]
=
(
unsigned
char
)
(
n
>>
8
);
ssl
->
out_msg
[
i
+
2
]
=
(
unsigned
char
)
(
n
);
i
+=
3
;
memcpy
(
ssl
->
out_msg
+
i
,
crt
->
raw
.
p
,
n
);
i
+=
n
;
crt
=
crt
->
next
;
}
ssl
->
out_msg
[
4
]
=
(
unsigned
char
)
((
i
-
7
)
>>
16
);
ssl
->
out_msg
[
5
]
=
(
unsigned
char
)
((
i
-
7
)
>>
8
);
ssl
->
out_msg
[
6
]
=
(
unsigned
char
)
((
i
-
7
));
ssl
->
out_msglen
=
i
;
ssl
->
out_msgtype
=
TLS_MSG_HANDSHAKE
;
ssl
->
out_msg
[
0
]
=
TLS_HS_CERTIFICATE
;
ssl
->
state
++
;
if
((
ret
=
ssl_write_record
(
ssl
))
!=
0
)
{
SSL_DEBUG_RET
(
1
,
"ssl_write_record"
,
ret
);
return
(
ret
);
}
debug_msg
(
2
,
"<= write certificate"
);
return
(
ret
);
}
int
_ntbtls_parse_certificate
(
ntbtls_t
ssl
)
{
int
ret
=
POLARSSL_ERR_SSL_FEATURE_UNAVAILABLE
;
size_t
i
,
n
;
const
ssl_ciphersuite_t
*
ciphersuite_info
=
ssl
->
transform_negotiate
->
ciphersuite_info
;
debug_msg
(
2
,
"=> parse certificate"
);
if
(
ciphersuite_info
->
key_exchange
==
POLARSSL_KEY_EXCHANGE_PSK
||
ciphersuite_info
->
key_exchange
==
POLARSSL_KEY_EXCHANGE_DHE_PSK
||
ciphersuite_info
->
key_exchange
==
POLARSSL_KEY_EXCHANGE_ECDHE_PSK
)
{
debug_msg
(
2
,
"<= skip parse certificate"
);
ssl
->
state
++
;
return
(
0
);
}
if
(
!
tls
->
is_client
&&
(
ssl
->
authmode
==
SSL_VERIFY_NONE
||
ciphersuite_info
->
key_exchange
==
POLARSSL_KEY_EXCHANGE_RSA_PSK
))
{
ssl
->
session_negotiate
->
verify_result
=
BADCERT_SKIP_VERIFY
;
debug_msg
(
2
,
"<= skip parse certificate"
);
ssl
->
state
++
;
return
(
0
);
}
if
((
ret
=
ssl_read_record
(
ssl
))
!=
0
)
{
SSL_DEBUG_RET
(
1
,
"ssl_read_record"
,
ret
);
return
(
ret
);
}
ssl
->
state
++
;
if
(
!
tls
->
is_client
&&
ssl
->
minor_ver
!=
SSL_MINOR_VERSION_0
)
{
if
(
ssl
->
in_hslen
==
7
&&
ssl
->
in_msgtype
==
TLS_MSG_HANDSHAKE
&&
ssl
->
in_msg
[
0
]
==
TLS_HS_CERTIFICATE
&&
memcmp
(
ssl
->
in_msg
+
4
,
"
\0\0\0
"
,
3
)
==
0
)
{
debug_msg
(
1
,
"TLSv1 client has no certificate"
);
ssl
->
session_negotiate
->
verify_result
=
BADCERT_MISSING
;
if
(
ssl
->
authmode
==
SSL_VERIFY_REQUIRED
)
return
(
POLARSSL_ERR_SSL_NO_CLIENT_CERTIFICATE
);
else
return
(
0
);
}
}
if
(
ssl
->
in_msgtype
!=
TLS_MSG_HANDSHAKE
)
{
debug_msg
(
1
,
"bad certificate message"
);
return
(
POLARSSL_ERR_SSL_UNEXPECTED_MESSAGE
);
}
if
(
ssl
->
in_msg
[
0
]
!=
TLS_HS_CERTIFICATE
||
ssl
->
in_hslen
<
10
)
{
debug_msg
(
1
,
"bad certificate message"
);
return
(
POLARSSL_ERR_SSL_BAD_HS_CERTIFICATE
);
}
/*
* Same message structure as in ssl_write_certificate()
*/
n
=
(
ssl
->
in_msg
[
5
]
<<
8
)
|
ssl
->
in_msg
[
6
];
if
(
ssl
->
in_msg
[
4
]
!=
0
||
ssl
->
in_hslen
!=
7
+
n
)
{
debug_msg
(
1
,
"bad certificate message"
);
return
(
POLARSSL_ERR_SSL_BAD_HS_CERTIFICATE
);
}
/* In case we tried to reuse a session but it failed */
if
(
ssl
->
session_negotiate
->
peer_cert
!=
NULL
)
{
x509_crt_free
(
ssl
->
session_negotiate
->
peer_cert
);
polarssl_free
(
ssl
->
session_negotiate
->
peer_cert
);
}
if
(
!
(
ssl
->
session_negotiate
->
peer_cert
=
malloc
(
sizeof
(
x509_crt
))))
{
err
=
gpg_error_from_syserror
();
debug_msg
(
1
,
"malloc(%d bytes) failed"
,
sizeof
(
x509_crt
));
return
err
;
}
x509_crt_init
(
ssl
->
session_negotiate
->
peer_cert
);
i
=
7
;
while
(
i
<
ssl
->
in_hslen
)
{
if
(
ssl
->
in_msg
[
i
]
!=
0
)
{
debug_msg
(
1
,
"bad certificate message"
);
return
(
POLARSSL_ERR_SSL_BAD_HS_CERTIFICATE
);
}
n
=
((
unsigned
int
)
ssl
->
in_msg
[
i
+
1
]
<<
8
)
|
(
unsigned
int
)
ssl
->
in_msg
[
i
+
2
];
i
+=
3
;
if
(
n
<
128
||
i
+
n
>
ssl
->
in_hslen
)
{
debug_msg
(
1
,
"bad certificate message"
);
return
(
POLARSSL_ERR_SSL_BAD_HS_CERTIFICATE
);
}
ret
=
x509_crt_parse_der
(
ssl
->
session_negotiate
->
peer_cert
,
ssl
->
in_msg
+
i
,
n
);
if
(
ret
!=
0
)
{
SSL_DEBUG_RET
(
1
,
" x509_crt_parse_der"
,
ret
);
return
(
ret
);
}
i
+=
n
;
}
SSL_DEBUG_CRT
(
3
,
"peer certificate"
,
ssl
->
session_negotiate
->
peer_cert
);
/*
* On client, make sure the server cert doesn't change during renego to
* avoid "triple handshake" attack: https://secure-resumption.com/
*/
if
(
tls
->
is_client
&&
ssl
->
renegotiation
==
TLS_RENEGOTIATION
)
{
if
(
ssl
->
session
->
peer_cert
==
NULL
)
{
debug_msg
(
1
,
"new server cert during renegotiation"
);
return
(
POLARSSL_ERR_SSL_BAD_HS_CERTIFICATE
);
}
if
(
ssl
->
session
->
peer_cert
->
raw
.
len
!=
ssl
->
session_negotiate
->
peer_cert
->
raw
.
len
||
memcmp
(
ssl
->
session
->
peer_cert
->
raw
.
p
,
ssl
->
session_negotiate
->
peer_cert
->
raw
.
p
,
ssl
->
session
->
peer_cert
->
raw
.
len
)
!=
0
)
{
debug_msg
(
1
,
"server cert changed during renegotiation"
);
return
(
POLARSSL_ERR_SSL_BAD_HS_CERTIFICATE
);
}
}
if
(
ssl
->
authmode
!=
SSL_VERIFY_NONE
)
{
if
(
ssl
->
ca_chain
==
NULL
)
{
debug_msg
(
1
,
"got no CA chain"
);
return
(
POLARSSL_ERR_SSL_CA_CHAIN_REQUIRED
);
}
/*
* Main check: verify certificate
*/
ret
=
x509_crt_verify
(
ssl
->
session_negotiate
->
peer_cert
,
ssl
->
ca_chain
,
ssl
->
ca_crl
,
ssl
->
peer_cn
,
&
ssl
->
session_negotiate
->
verify_result
,
ssl
->
f_vrfy
,
ssl
->
p_vrfy
);
if
(
ret
!=
0
)
{
SSL_DEBUG_RET
(
1
,
"x509_verify_cert"
,
ret
);
}
/*
* Secondary checks: always done, but change 'ret' only if it was 0
*/
{
pk_context
*
pk
=
&
ssl
->
session_negotiate
->
peer_cert
->
pk
;
/* If certificate uses an EC key, make sure the curve is OK */
if
(
pk_can_do
(
pk
,
POLARSSL_PK_ECKEY
)
&&
!
ssl_curve_is_acceptable
(
ssl
,
pk_ec
(
*
pk
)
->
grp
.
id
))
{
debug_msg
(
1
,
"bad certificate (EC key curve)"
);
if
(
ret
==
0
)
ret
=
POLARSSL_ERR_SSL_BAD_HS_CERTIFICATE
;
}
}
if
(
ssl_check_cert_usage
(
ssl
->
session_negotiate
->
peer_cert
,
ciphersuite_info
,
tls
->
is_client
)
!=
0
)
{
debug_msg
(
1
,
"bad certificate (usage extensions)"
);
if
(
ret
==
0
)
ret
=
POLARSSL_ERR_SSL_BAD_HS_CERTIFICATE
;
}
if
(
ssl
->
authmode
!=
SSL_VERIFY_REQUIRED
)
ret
=
0
;
}
debug_msg
(
2
,
"<= parse certificate"
);
return
(
ret
);
}
int
_ntbtls_write_change_cipher_spec
(
ntbtls_t
ssl
)
{
int
ret
;
debug_msg
(
2
,
"=> write change cipher spec"
);
ssl
->
out_msgtype
=
TLS_MSG_CHANGE_CIPHER_SPEC
;
ssl
->
out_msglen
=
1
;
ssl
->
out_msg
[
0
]
=
1
;
ssl
->
state
++
;
if
((
ret
=
ssl_write_record
(
ssl
))
!=
0
)
{
SSL_DEBUG_RET
(
1
,
"ssl_write_record"
,
ret
);
return
(
ret
);
}
debug_msg
(
2
,
"<= write change cipher spec"
);
return
(
0
);
}
int
_ntbtls_parse_change_cipher_spec
(
ntbtls_t
ssl
)
{
int
ret
;
debug_msg
(
2
,
"=> parse change cipher spec"
);
if
((
ret
=
ssl_read_record
(
ssl
))
!=
0
)
{
SSL_DEBUG_RET
(
1
,
"ssl_read_record"
,
ret
);
return
(
ret
);
}
if
(
ssl
->
in_msgtype
!=
TLS_MSG_CHANGE_CIPHER_SPEC
)
{
debug_msg
(
1
,
"bad change cipher spec message"
);
return
(
POLARSSL_ERR_SSL_UNEXPECTED_MESSAGE
);
}
if
(
ssl
->
in_msglen
!=
1
||
ssl
->
in_msg
[
0
]
!=
1
)
{
debug_msg
(
1
,
"bad change cipher spec message"
);
return
(
POLARSSL_ERR_SSL_BAD_HS_CHANGE_CIPHER_SPEC
);
}
ssl
->
state
++
;
debug_msg
(
2
,
"<= parse change cipher spec"
);
return
(
0
);
}
void
ssl_optimize_checksum
(
ntbtls_t
ssl
,
const
ssl_ciphersuite_t
*
ciphersuite_info
)
{
if
(
ciphersuite_info
->
mac
==
GCRY_MD_SHA384
)
ssl
->
handshake
->
update_checksum
=
update_checksum_sha384
;
else
if
(
ciphersuite_info
->
mac
!=
GCRY_MD_SHA384
)
ssl
->
handshake
->
update_checksum
=
update_checksum_sha256
;
else
{
debug_bug
();
return
;
}
}
static
void
update_checksum_start
(
ntbtls_t
ssl
,
const
unsigned
char
*
buf
,
size_t
len
)
{
sha256_update
(
&
ssl
->
handshake
->
fin_sha256
,
buf
,
len
);
sha512_update
(
&
ssl
->
handshake
->
fin_sha512
,
buf
,
len
);
}
static
void
update_checksum_sha256
(
ntbtls_t
ssl
,
const
unsigned
char
*
buf
,
size_t
len
)
{
sha256_update
(
&
ssl
->
handshake
->
fin_sha256
,
buf
,
len
);
}
static
void
update_checksum_sha384
(
ntbtls_t
ssl
,
const
unsigned
char
*
buf
,
size_t
len
)
{
sha512_update
(
&
ssl
->
handshake
->
fin_sha512
,
buf
,
len
);
}
static
void
calc_finished_tls_sha256
(
ntbtls_t
ssl
,
unsigned
char
*
buf
,
int
is_client
)
{
int
len
=
12
;
const
char
*
sender
;
sha256_context
sha256
;
unsigned
char
padbuf
[
32
];
session_t
session
=
ssl
->
session_negotiate
;
if
(
!
session
)
session
=
ssl
->
session
;
debug_msg
(
2
,
"=> calc finished tls sha256"
);
memcpy
(
&
sha256
,
&
ssl
->
handshake
->
fin_sha256
,
sizeof
(
sha256_context
));
/*
* TLSv1.2:
* hash = PRF( master, finished_label,
* Hash( handshake ) )[0.11]
*/
#if !defined(POLARSSL_SHA256_ALT)
debug_buf
(
4
,
"finished sha2 state"
,
sha256
.
state
,
sizeof
(
sha256
.
state
));
#endif
sender
=
is_client
?
"client finished"
:
"server finished"
;
sha256_finish
(
&
sha256
,
padbuf
);
ssl
->
handshake
->
tls_prf
(
session
->
master
,
48
,
sender
,
padbuf
,
32
,
buf
,
len
);
debug_buf
(
3
,
"calc finished result"
,
buf
,
len
);
sha256_free
(
&
sha256
);
wipememory
(
padbuf
,
sizeof
(
padbuf
));
debug_msg
(
2
,
"<= calc finished"
);
}
static
void
calc_finished_tls_sha384
(
ntbtls_t
ssl
,
unsigned
char
*
buf
,
int
is_client
)
{
int
len
=
12
;
const
char
*
sender
;
sha512_context
sha512
;
unsigned
char
padbuf
[
48
];
session_t
session
=
ssl
->
session_negotiate
;
if
(
!
session
)
session
=
ssl
->
session
;
debug_msg
(
2
,
"=> calc finished tls sha384"
);
memcpy
(
&
sha512
,
&
ssl
->
handshake
->
fin_sha512
,
sizeof
(
sha512_context
));
/*
* TLSv1.2:
* hash = PRF( master, finished_label,
* Hash( handshake ) )[0.11]
*/
#if !defined(POLARSSL_SHA512_ALT)
debug_buf
(
4
,
"finished sha512 state"
,
sha512
.
state
,
sizeof
(
sha512
.
state
));
#endif
sender
=
is_client
?
"client finished"
:
"server finished"
;
sha512_finish
(
&
sha512
,
padbuf
);
ssl
->
handshake
->
tls_prf
(
session
->
master
,
48
,
sender
,
padbuf
,
48
,
buf
,
len
);
debug_buf
(
3
,
"calc finished result"
,
buf
,
len
);
sha512_free
(
&
sha512
);
wipememory
(
padbuf
,
sizeof
(
padbuf
));
debug_msg
(
2
,
"<= calc finished"
);
}
void
_ntbtls_handshake_wrapup
(
ntbtls_t
ssl
)
{
int
resume
=
ssl
->
handshake
->
resume
;
debug_msg
(
3
,
"=> handshake wrapup"
);
/*
* Free our handshake params
*/
ssl_handshake_free
(
ssl
->
handshake
);
polarssl_free
(
ssl
->
handshake
);
ssl
->
handshake
=
NULL
;
if
(
ssl
->
renegotiation
==
TLS_RENEGOTIATION
)
{
ssl
->
renegotiation
=
TLS_RENEGOTIATION_DONE
;
ssl
->
renego_records_seen
=
0
;
}
/*
* Switch in our now active transform context
*/
if
(
ssl
->
transform
)
{
ssl_transform_free
(
ssl
->
transform
);
polarssl_free
(
ssl
->
transform
);
}
ssl
->
transform
=
ssl
->
transform_negotiate
;
ssl
->
transform_negotiate
=
NULL
;
if
(
ssl
->
session
)
{
session_free
(
ssl
->
session
);
polarssl_free
(
ssl
->
session
);
}
ssl
->
session
=
ssl
->
session_negotiate
;
ssl
->
session_negotiate
=
NULL
;
/*
* Add cache entry
*/
if
(
ssl
->
f_set_cache
!=
NULL
&&
ssl
->
session
->
length
!=
0
&&
resume
==
0
)
{
if
(
ssl
->
f_set_cache
(
ssl
->
p_set_cache
,
ssl
->
session
)
!=
0
)
debug_msg
(
1
,
"cache did not store session"
);
}
ssl
->
state
++
;
debug_msg
(
3
,
"<= handshake wrapup"
);
}
int
_ntbtls_write_finished
(
ntbtls_t
ssl
)
{
int
ret
,
hash_len
;
debug_msg
(
2
,
"=> write finished"
);
/*
* Set the out_msg pointer to the correct location based on IV length
*/
if
(
ssl
->
minor_ver
>=
SSL_MINOR_VERSION_2
)
{
ssl
->
out_msg
=
ssl
->
out_iv
+
ssl
->
transform_negotiate
->
ivlen
-
ssl
->
transform_negotiate
->
fixed_ivlen
;
}
else
ssl
->
out_msg
=
ssl
->
out_iv
;
ssl
->
handshake
->
calc_finished
(
ssl
,
ssl
->
out_msg
+
4
,
ssl
->
is_client
);
// TODO TLS/1.2 Hash length is determined by cipher suite (Page 63)
hash_len
=
(
ssl
->
minor_ver
==
SSL_MINOR_VERSION_0
)
?
36
:
12
;
ssl
->
verify_data_len
=
hash_len
;
memcpy
(
ssl
->
own_verify_data
,
ssl
->
out_msg
+
4
,
hash_len
);
ssl
->
out_msglen
=
4
+
hash_len
;
ssl
->
out_msgtype
=
TLS_MSG_HANDSHAKE
;
ssl
->
out_msg
[
0
]
=
TLS_HS_FINISHED
;
/*
* In case of session resuming, invert the client and server
* ChangeCipherSpec messages order.
*/
if
(
ssl
->
handshake
->
resume
!=
0
)
{
if
(
ssl
->
is_client
)
ssl
->
state
=
SSL_HANDSHAKE_WRAPUP
;
else
ssl
->
state
=
SSL_CLIENT_CHANGE_CIPHER_SPEC
;
}
else
ssl
->
state
++
;
/*
* Switch to our negotiated transform and session parameters for outbound
* data.
*/
debug_msg
(
3
,
"switching to new transform spec for outbound data"
);
ssl
->
transform_out
=
ssl
->
transform_negotiate
;
ssl
->
session_out
=
ssl
->
session_negotiate
;
memset
(
ssl
->
out_ctr
,
0
,
8
);
if
((
ret
=
ssl_write_record
(
ssl
))
!=
0
)
{
SSL_DEBUG_RET
(
1
,
"ssl_write_record"
,
ret
);
return
(
ret
);
}
debug_msg
(
2
,
"<= write finished"
);
return
(
0
);
}
int
_ntbtls_parse_finished
(
ntbtls_t
ssl
)
{
int
ret
;
unsigned
int
hash_len
;
unsigned
char
buf
[
36
];
debug_msg
(
2
,
"=> parse finished"
);
ssl
->
handshake
->
calc_finished
(
ssl
,
buf
,
tls
->
is_client
);
/*
* Switch to our negotiated transform and session parameters for inbound
* data.
*/
debug_msg
(
3
,
"switching to new transform spec for inbound data"
);
ssl
->
transform_in
=
ssl
->
transform_negotiate
;
ssl
->
session_in
=
ssl
->
session_negotiate
;
memset
(
ssl
->
in_ctr
,
0
,
8
);
/*
* Set the in_msg pointer to the correct location based on IV length
*/
if
(
ssl
->
minor_ver
>=
SSL_MINOR_VERSION_2
)
{
ssl
->
in_msg
=
ssl
->
in_iv
+
ssl
->
transform_negotiate
->
ivlen
-
ssl
->
transform_negotiate
->
fixed_ivlen
;
}
else
ssl
->
in_msg
=
ssl
->
in_iv
;
if
((
ret
=
ssl_read_record
(
ssl
))
!=
0
)
{
SSL_DEBUG_RET
(
1
,
"ssl_read_record"
,
ret
);
return
(
ret
);
}
if
(
ssl
->
in_msgtype
!=
TLS_MSG_HANDSHAKE
)
{
debug_msg
(
1
,
"bad finished message"
);
return
(
POLARSSL_ERR_SSL_UNEXPECTED_MESSAGE
);
}
// TODO TLS/1.2 Hash length is determined by cipher suite (Page 63)
hash_len
=
(
ssl
->
minor_ver
==
SSL_MINOR_VERSION_0
)
?
36
:
12
;
if
(
ssl
->
in_msg
[
0
]
!=
TLS_HS_FINISHED
||
ssl
->
in_hslen
!=
4
+
hash_len
)
{
debug_msg
(
1
,
"bad finished message"
);
return
(
POLARSSL_ERR_SSL_BAD_HS_FINISHED
);
}
if
(
safer_memcmp
(
ssl
->
in_msg
+
4
,
buf
,
hash_len
)
!=
0
)
{
debug_msg
(
1
,
"bad finished message"
);
return
(
POLARSSL_ERR_SSL_BAD_HS_FINISHED
);
}
ssl
->
verify_data_len
=
hash_len
;
memcpy
(
ssl
->
peer_verify_data
,
buf
,
hash_len
);
if
(
ssl
->
handshake
->
resume
!=
0
)
{
if
(
ssl
->
is_client
)
ssl
->
state
=
SSL_CLIENT_CHANGE_CIPHER_SPEC
;
else
ssl
->
state
=
SSL_HANDSHAKE_WRAPUP
;
}
else
ssl
->
state
++
;
debug_msg
(
2
,
"<= parse finished"
);
return
(
0
);
}
static
void
transform_init
(
ssl_transform
*
transform
)
{
memset
(
transform
,
0
,
sizeof
(
ssl_transform
));
cipher_init
(
&
transform
->
cipher_ctx_enc
);
cipher_init
(
&
transform
->
cipher_ctx_dec
);
md_init
(
&
transform
->
md_ctx_enc
);
md_init
(
&
transform
->
md_ctx_dec
);
}
static
void
session_init
(
session_t
session
)
{
memset
(
session
,
0
,
sizeof
*
session
);
}
static
void
handshake_params_init
(
ssl_handshake_params
*
handshake
)
{
memset
(
handshake
,
0
,
sizeof
(
ssl_handshake_params
));
sha256_init
(
&
handshake
->
fin_sha256
);
sha256_starts
(
&
handshake
->
fin_sha256
,
0
);
sha512_init
(
&
handshake
->
fin_sha512
);
sha512_starts
(
&
handshake
->
fin_sha512
,
1
);
handshake
->
update_checksum
=
update_checksum_start
;
handshake
->
sig_alg
=
SSL_HASH_SHA1
;
dhm_init
(
&
handshake
->
dhm_ctx
);
ecdh_init
(
&
handshake
->
ecdh_ctx
);
}
static
gpg_error_t
handshake_init
(
ntbtls_t
tls
)
{
gpg_error_t
err
;
/* Clear old handshake information if present. */
transform_free
(
tls
->
transform_negotiate
);
session_free
(
tls
->
session_negotiate
);
handshake_free
(
tls
->
handshake
);
/*
* Either the pointers are now NULL or cleared properly and can be freed.
* Now allocate missing structures.
*/
if
(
!
tls
->
transform_negotiate
)
{
tls
->
transform_negotiate
=
malloc
(
sizeof
*
tls
->
transform_negotiate
);
if
(
!
tls
->
transform_negotiate
)
{
err
=
gpg_error_from_syserror
();
goto
leave
;
}
}
if
(
!
tls
->
session_negotiate
)
{
tls
->
session_negotiate
=
malloc
(
sizeof
*
tls
->
session_negotiate
);
if
(
!
tls
->
session_negotiate
)
{
err
=
gpg_error_from_syserror
();
goto
leave
;
}
}
if
(
!
tls
->
handshake
)
{
tls
->
handshake
=
malloc
(
sizeof
*
tls
->
handshake
);
if
(
!
tls
->
handshake
)
{
err
=
gpg_error_from_syserror
();
goto
leave
;
}
}
/* Initialize structures */
session_init
(
tls
->
session_negotiate
);
transform_init
(
tls
->
transform_negotiate
);
handshake_params_init
(
tls
->
handshake
);
/* Fixme: Document the owner of KEY_CERT or use a ref counter. */
tls
->
handshake
->
key_cert
=
tls
->
key_cert
;
leave
:
if
(
err
)
{
xfree
(
tls
->
transform_negotiate
);
tls
->
transform_negotiate
=
NULL
;
xfree
(
tls
->
session_negotiate
);
tls
->
session_negotiate
=
NULL
;
xfree
(
tls
->
handshake
);
tls
->
handshake
=
NULL
;
}
return
err
;
}
/*
* Initialize an TLS context. Valid values for FLAGS are:
*
* NTBTLS_INIT_SERVER - This endpoint is a server (default).
* NTBTLS_INIT_CLIENT - This endpoint is a client.
*
* On success a context object is returned at R_TLS. One error NULL
* is stored at R_TLS and an error code is returned.
*/
gpg_error_t
_ntbtls_init
(
ntbtls_t
*
r_tls
,
unsigned
int
flags
)
{
gpg_error_t
err
;
ntbtls_t
tls
;
int
buffer_len
=
TLS_BUFFER_LEN
;
*
r_tls
=
NULL
;
tls
=
calloc
(
1
,
sizeof
*
tls
);
if
(
!
tls
)
return
gpg_error_from_syserror
();
/* Return immediately. */
tls
->
min_major_ver
=
TLS_MIN_MAJOR_VERSION
;
tls
->
min_minor_ver
=
TLS_MIN_MINOR_VERSION
;
tls
->
max_major_ver
=
TLS_MAX_MAJOR_VERSION
;
tls
->
max_minor_ver
=
TLS_MAX_MINOR_VERSION
;
/* FIXME: ssl_set_ciphersuites (ssl, ssl_list_ciphersuites ()); */
tls
->
renego_max_records
=
TLS_RENEGO_MAX_RECORDS_DEFAULT
;
/* FIXME */
/* if ((ret = mpi_read_string (&tls->dhm_P, 16, */
/* POLARSSL_DHM_RFC5114_MODP_1024_P)) != 0 || */
/* (ret = mpi_read_string (&tls->dhm_G, 16, */
/* POLARSSL_DHM_RFC5114_MODP_1024_G)) != 0) */
/* { */
/* SSL_DEBUG_RET (1, "mpi_read_string", ret); */
/* return (ret); */
/* } */
/*
* Prepare base structures
*/
tls
->
in_ctr
=
malloc
(
buffer_len
);
if
(
!
tls
->
in_ctr
)
{
err
=
gpg_error_from_syserror
();
goto
leave
;
}
tls
->
in_hdr
=
tls
->
in_ctr
+
8
;
tls
->
in_iv
=
tls
->
in_ctr
+
13
;
tls
->
in_msg
=
tls
->
in_ctr
+
13
;
tls
->
out_ctr
=
malloc
(
bufer_len
);
if
(
!
tls
->
out_ctr
)
{
err
=
gpg_error_from_syserror
();
goto
leave
;
}
tls
->
out_hdr
=
tls
->
out_ctr
+
8
;
tls
->
out_iv
=
tls
->
out_ctr
+
13
;
tls
->
out_msg
=
tls
->
out_ctr
+
13
;
memset
(
tls
->
in_ctr
,
0
,
buffer_len
);
memset
(
tls
->
out_ctr
,
0
,
buffer_len
);
tls
->
ticket_lifetime
=
TLS_DEFAULT_TICKET_LIFETIME
;
// FIXME: tls->curve_list = ecp_grp_id_list ();
err
=
handshake_init
(
tls
);
if
(
err
)
goto
leave
;
if
(
tls
->
is_client
)
tls
->
session_tickets
=
SSL_SESSION_TICKETS_ENABLED
;
leave
:
if
(
err
)
{
xfree
(
tls
->
in_ctr
);
xfree
(
tls
);
}
else
*
r_tls
=
tls
;
return
err
;
}
/* Set the transport stream for the context TLS. This needs to be
called right after init and may not be changed later. INBOUND and
OUTBOIUND are usually connected to the same socket. The caller
must ensure that the streams are not closed as long as the context
TLS is valid. However, after destroying the context the streams
may be closed. This behavior allows to setup a TLS connection on
an existing stream, shutdown the TLS and continue unencrypted.
Whether the latter is of any real use in practice is a different
question. Using separate streams allow to run TLS over a pair of
half-duplex connections. */
gpg_error_t
_ntbtls_set_transport
(
ntbtls_t
tls
,
estream_t
inbound
,
estream_t
outbound
)
{
if
(
!
tls
||
!
inbound
||
!
outbound
)
return
gpg_error
(
GPG_ERR_INV_ARG
);
if
(
tls
->
inbound
||
tls
->
outbound
)
return
gpg_error
(
GPG_ERR_CONFLICT
);
tls
->
inbound
=
inbound
;
tls
->
outbound
=
outbound
;
return
0
;
}
/* Return the two streams used to read and write the plaintext. the
streams are valid as along as TLS is valid and may thus not be used
after TLS has been destroyed. */
gpg_error_t
_ntbtls_get_stream
(
ntbtls_t
tls
,
estream_t
*
r_readfp
,
estream_t
*
r_writefp
)
{
//FIXME
}
/*
* Reset an initialized and used SSL context for re-use while retaining
* all application-set variables, function pointers and data.
*/
int
ssl_session_reset
(
ntbtls_t
ssl
)
{
int
ret
;
ssl
->
state
=
TLS_HELLO_REQUEST
;
ssl
->
renegotiation
=
TLS_INITIAL_HANDSHAKE
;
ssl
->
secure_renegotiation
=
TLS_LEGACY_RENEGOTIATION
;
ssl
->
verify_data_len
=
0
;
memset
(
ssl
->
own_verify_data
,
0
,
36
);
memset
(
ssl
->
peer_verify_data
,
0
,
36
);
ssl
->
in_offt
=
NULL
;
ssl
->
in_msg
=
ssl
->
in_ctr
+
13
;
ssl
->
in_msgtype
=
0
;
ssl
->
in_msglen
=
0
;
ssl
->
in_left
=
0
;
ssl
->
in_hslen
=
0
;
ssl
->
nb_zero
=
0
;
ssl
->
record_read
=
0
;
ssl
->
out_msg
=
ssl
->
out_ctr
+
13
;
ssl
->
out_msgtype
=
0
;
ssl
->
out_msglen
=
0
;
ssl
->
out_left
=
0
;
ssl
->
transform_in
=
NULL
;
ssl
->
transform_out
=
NULL
;
ssl
->
renego_records_seen
=
0
;
memset
(
ssl
->
out_ctr
,
0
,
SSL_BUFFER_LEN
);
memset
(
ssl
->
in_ctr
,
0
,
SSL_BUFFER_LEN
);
if
(
ssl
->
transform
)
{
ssl_transform_free
(
ssl
->
transform
);
polarssl_free
(
ssl
->
transform
);
ssl
->
transform
=
NULL
;
}
if
(
ssl
->
session
)
{
session_free
(
ssl
->
session
);
polarssl_free
(
ssl
->
session
);
ssl
->
session
=
NULL
;
}
ssl
->
alpn_chosen
=
NULL
;
if
((
ret
=
handshake_init
(
ssl
))
!=
0
)
return
(
ret
);
return
(
0
);
}
static
void
ssl_ticket_keys_free
(
ssl_ticket_keys
*
tkeys
)
{
aes_free
(
&
tkeys
->
enc
);
aes_free
(
&
tkeys
->
dec
);
wipememory
(
tkeys
,
sizeof
(
ssl_ticket_keys
));
}
/*
* Allocate and initialize ticket keys
*/
static
int
ssl_ticket_keys_init
(
ntbtls_t
ssl
)
{
int
ret
;
ssl_ticket_keys
*
tkeys
;
unsigned
char
buf
[
16
];
if
(
ssl
->
ticket_keys
!=
NULL
)
return
(
0
);
tkeys
=
malloc
(
sizeof
*
tkeys
);
if
(
!
tkeys
)
return
gpg_error_from_syserror
()
aes_init
(
&
tkeys
->
enc
);
aes_init
(
&
tkeys
->
dec
);
if
((
ret
=
ssl
->
f_rng
(
ssl
->
p_rng
,
tkeys
->
key_name
,
16
))
!=
0
)
{
ssl_ticket_keys_free
(
tkeys
);
polarssl_free
(
tkeys
);
return
(
ret
);
}
if
((
ret
=
ssl
->
f_rng
(
ssl
->
p_rng
,
buf
,
16
))
!=
0
||
(
ret
=
aes_setkey_enc
(
&
tkeys
->
enc
,
buf
,
128
))
!=
0
||
(
ret
=
aes_setkey_dec
(
&
tkeys
->
dec
,
buf
,
128
))
!=
0
)
{
ssl_ticket_keys_free
(
tkeys
);
polarssl_free
(
tkeys
);
return
(
ret
);
}
if
((
ret
=
ssl
->
f_rng
(
ssl
->
p_rng
,
tkeys
->
mac_key
,
16
))
!=
0
)
{
ssl_ticket_keys_free
(
tkeys
);
polarssl_free
(
tkeys
);
return
(
ret
);
}
ssl
->
ticket_keys
=
tkeys
;
return
(
0
);
}
/*
* SSL set accessors
*/
void
ssl_set_authmode
(
ntbtls_t
ssl
,
int
authmode
)
{
ssl
->
authmode
=
authmode
;
}
#if defined(POLARSSL_X509_CRT_PARSE_C)
void
ssl_set_verify
(
ntbtls_t
ssl
,
int
(
*
f_vrfy
)
(
void
*
,
x509_crt
*
,
int
,
int
*
),
void
*
p_vrfy
)
{
ssl
->
f_vrfy
=
f_vrfy
;
ssl
->
p_vrfy
=
p_vrfy
;
}
#endif
/* POLARSSL_X509_CRT_PARSE_C */
void
ssl_set_rng
(
ntbtls_t
ssl
,
int
(
*
f_rng
)
(
void
*
,
unsigned
char
*
,
size_t
),
void
*
p_rng
)
{
ssl
->
f_rng
=
f_rng
;
ssl
->
p_rng
=
p_rng
;
}
void
ssl_set_dbg
(
ntbtls_t
ssl
,
void
(
*
f_dbg
)
(
void
*
,
int
,
const
char
*
),
void
*
p_dbg
)
{
ssl
->
f_dbg
=
f_dbg
;
ssl
->
p_dbg
=
p_dbg
;
}
void
ssl_set_bio
(
ntbtls_t
ssl
,
int
(
*
f_recv
)
(
void
*
,
unsigned
char
*
,
size_t
),
void
*
p_recv
,
int
(
*
f_send
)
(
void
*
,
const
unsigned
char
*
,
size_t
),
void
*
p_send
)
{
ssl
->
f_recv
=
f_recv
;
ssl
->
f_send
=
f_send
;
ssl
->
p_recv
=
p_recv
;
ssl
->
p_send
=
p_send
;
}
void
ssl_set_session_cache
(
ntbtls_t
ssl
,
int
(
*
f_get_cache
)
(
void
*
,
session_t
),
void
*
p_get_cache
,
int
(
*
f_set_cache
)
(
void
*
,
const
session_t
),
void
*
p_set_cache
)
{
ssl
->
f_get_cache
=
f_get_cache
;
ssl
->
p_get_cache
=
p_get_cache
;
ssl
->
f_set_cache
=
f_set_cache
;
ssl
->
p_set_cache
=
p_set_cache
;
}
int
ssl_set_session
(
ntbtls_t
ssl
,
const
session_t
session
)
{
int
ret
;
if
(
ssl
==
NULL
||
session
==
NULL
||
ssl
->
session_negotiate
==
NULL
||
!
ssl
->
is_client
)
{
return
(
POLARSSL_ERR_SSL_BAD_INPUT_DATA
);
}
if
((
ret
=
ssl_session_copy
(
ssl
->
session_negotiate
,
session
))
!=
0
)
return
(
ret
);
ssl
->
handshake
->
resume
=
1
;
return
(
0
);
}
void
ssl_set_ciphersuites
(
ntbtls_t
ssl
,
const
int
*
ciphersuites
)
{
ssl
->
ciphersuite_list
[
SSL_MINOR_VERSION_0
]
=
ciphersuites
;
ssl
->
ciphersuite_list
[
SSL_MINOR_VERSION_1
]
=
ciphersuites
;
ssl
->
ciphersuite_list
[
SSL_MINOR_VERSION_2
]
=
ciphersuites
;
ssl
->
ciphersuite_list
[
SSL_MINOR_VERSION_3
]
=
ciphersuites
;
}
void
ssl_set_ciphersuites_for_version
(
ntbtls_t
ssl
,
const
int
*
ciphersuites
,
int
major
,
int
minor
)
{
if
(
major
!=
SSL_MAJOR_VERSION_3
)
return
;
if
(
minor
<
SSL_MINOR_VERSION_0
||
minor
>
SSL_MINOR_VERSION_3
)
return
;
ssl
->
ciphersuite_list
[
minor
]
=
ciphersuites
;
}
/* Add a new (empty) key_cert entry an return a pointer to it */
static
ssl_key_cert
*
ssl_add_key_cert
(
ntbtls_t
ssl
)
{
ssl_key_cert
*
key_cert
,
*
last
;
key_cert
=
calloc
(
1
,
sizeof
*
key_cert
);
if
(
!
key_cert
)
return
NULL
;
/* Append the new key_cert to the (possibly empty) current list */
if
(
ssl
->
key_cert
==
NULL
)
{
ssl
->
key_cert
=
key_cert
;
if
(
ssl
->
handshake
!=
NULL
)
ssl
->
handshake
->
key_cert
=
key_cert
;
}
else
{
last
=
ssl
->
key_cert
;
while
(
last
->
next
!=
NULL
)
last
=
last
->
next
;
last
->
next
=
key_cert
;
}
return
(
key_cert
);
}
void
ssl_set_ca_chain
(
ntbtls_t
ssl
,
x509_crt
*
ca_chain
,
x509_crl
*
ca_crl
,
const
char
*
peer_cn
)
{
ssl
->
ca_chain
=
ca_chain
;
ssl
->
ca_crl
=
ca_crl
;
ssl
->
peer_cn
=
peer_cn
;
}
int
ssl_set_own_cert
(
ntbtls_t
ssl
,
x509_crt
*
own_cert
,
pk_context
*
pk_key
)
{
ssl_key_cert
*
key_cert
;
key_cert
=
ssl_add_key_cert
(
ssl
);
if
(
!
key_cert
)
return
gpg_error_from_syserror
();
key_cert
->
cert
=
own_cert
;
key_cert
->
key
=
pk_key
;
return
0
;
}
int
ssl_set_own_cert_rsa
(
ntbtls_t
ssl
,
x509_crt
*
own_cert
,
rsa_context
*
rsa_key
)
{
int
ret
;
ssl_key_cert
*
key_cert
;
key_cert
=
ssl_add_key_cert
(
ssl
);
if
(
!
key_cert
)
return
gpg_error_from_syserror
();
key_cert
->
key
=
malloc
(
sizeof
(
pk_context
));
if
(
!
key_cert
->
key
)
return
gpg_error_from_syserror
();
pk_init
(
key_cert
->
key
);
ret
=
pk_init_ctx
(
key_cert
->
key
,
pk_info_from_type
(
POLARSSL_PK_RSA
));
if
(
ret
!=
0
)
return
(
ret
);
if
((
ret
=
rsa_copy
(
pk_rsa
(
*
key_cert
->
key
),
rsa_key
))
!=
0
)
return
(
ret
);
key_cert
->
cert
=
own_cert
;
key_cert
->
key_own_alloc
=
1
;
return
(
0
);
}
int
ssl_set_own_cert_alt
(
ntbtls_t
ssl
,
x509_crt
*
own_cert
,
void
*
rsa_key
,
rsa_decrypt_func
rsa_decrypt
,
rsa_sign_func
rsa_sign
,
rsa_key_len_func
rsa_key_len
)
{
int
ret
;
ssl_key_cert
*
key_cert
;
key_cert
=
ssl_add_key_cert
(
ssl
);
if
(
!
key_cert
)
return
gpg_error_from_syserror
();
key_cert
->
key
=
malloc
(
sizeof
(
pk_context
));
if
(
!
key_cert
->
key
)
{
err
=
gpg_error_from_syserror
();
free
(
key_cert
);
return
err
;
}
pk_init
(
key_cert
->
key
);
if
((
ret
=
pk_init_ctx_rsa_alt
(
key_cert
->
key
,
rsa_key
,
rsa_decrypt
,
rsa_sign
,
rsa_key_len
))
!=
0
)
return
(
ret
);
key_cert
->
cert
=
own_cert
;
key_cert
->
key_own_alloc
=
1
;
return
0
;
}
int
ssl_set_psk
(
ntbtls_t
ssl
,
const
unsigned
char
*
psk
,
size_t
psk_len
,
const
unsigned
char
*
psk_identity
,
size_t
psk_identity_len
)
{
if
(
psk
==
NULL
||
psk_identity
==
NULL
)
return
(
POLARSSL_ERR_SSL_BAD_INPUT_DATA
);
if
(
psk_len
>
POLARSSL_PSK_MAX_LEN
)
return
(
POLARSSL_ERR_SSL_BAD_INPUT_DATA
);
if
(
ssl
->
psk
!=
NULL
)
{
free
(
ssl
->
psk
);
ssl
->
psk
=
NULL
;
free
(
ssl
->
psk_identity
);
ssl
->
psk_identity
=
NULL
;
}
ssl
->
psk_len
=
psk_len
;
ssl
->
psk_identity_len
=
psk_identity_len
;
ssl
->
psk
=
malloc
(
ssl
->
psk_len
);
if
(
!
ssl
->
psk
)
return
gpg_error_from_syserror
();
ssl
->
psk_identity
=
malloc
(
ssl
->
psk_identity_len
);
if
(
!
ssl
->
psk_identity
)
{
err
=
gpg_error_from_syserror
();
free
(
ssl
->
psk
);
ssl
->
psk
=
NULL
;
return
err
;
}
memcpy
(
ssl
->
psk
,
psk
,
ssl
->
psk_len
);
memcpy
(
ssl
->
psk_identity
,
psk_identity
,
ssl
->
psk_identity_len
);
return
(
0
);
}
void
ssl_set_psk_cb
(
ntbtls_t
ssl
,
int
(
*
f_psk
)
(
void
*
,
ssl_context
*
,
const
unsigned
char
*
,
size_t
),
void
*
p_psk
)
{
ssl
->
f_psk
=
f_psk
;
ssl
->
p_psk
=
p_psk
;
}
int
ssl_set_dh_param
(
ntbtls_t
ssl
,
const
char
*
dhm_P
,
const
char
*
dhm_G
)
{
int
ret
;
if
((
ret
=
mpi_read_string
(
&
ssl
->
dhm_P
,
16
,
dhm_P
))
!=
0
)
{
SSL_DEBUG_RET
(
1
,
"mpi_read_string"
,
ret
);
return
(
ret
);
}
if
((
ret
=
mpi_read_string
(
&
ssl
->
dhm_G
,
16
,
dhm_G
))
!=
0
)
{
SSL_DEBUG_RET
(
1
,
"mpi_read_string"
,
ret
);
return
(
ret
);
}
return
(
0
);
}
int
ssl_set_dh_param_ctx
(
ntbtls_t
ssl
,
dhm_context
*
dhm_ctx
)
{
int
ret
;
if
((
ret
=
mpi_copy
(
&
ssl
->
dhm_P
,
&
dhm_ctx
->
P
))
!=
0
)
{
SSL_DEBUG_RET
(
1
,
"mpi_copy"
,
ret
);
return
(
ret
);
}
if
((
ret
=
mpi_copy
(
&
ssl
->
dhm_G
,
&
dhm_ctx
->
G
))
!=
0
)
{
SSL_DEBUG_RET
(
1
,
"mpi_copy"
,
ret
);
return
(
ret
);
}
return
(
0
);
}
/*
* Set the allowed elliptic curves
*/
void
ssl_set_curves
(
ntbtls_t
ssl
,
const
ecp_group_id
*
curve_list
)
{
ssl
->
curve_list
=
curve_list
;
}
int
ssl_set_hostname
(
ntbtls_t
ssl
,
const
char
*
hostname
)
{
if
(
hostname
==
NULL
)
return
(
POLARSSL_ERR_SSL_BAD_INPUT_DATA
);
ssl
->
hostname_len
=
strlen
(
hostname
);
if
(
ssl
->
hostname_len
+
1
==
0
)
return
(
POLARSSL_ERR_SSL_BAD_INPUT_DATA
);
ssl
->
hostname
=
malloc
(
ssl
->
hostname_len
+
1
);
if
(
!
ssl
->
hostname
)
return
gpg_error_from_syserror
();
memcpy
(
ssl
->
hostname
,
hostname
,
ssl
->
hostname_len
);
ssl
->
hostname
[
ssl
->
hostname_len
]
=
'\0'
;
return
0
;
}
void
ssl_set_sni
(
ntbtls_t
ssl
,
int
(
*
f_sni
)
(
void
*
,
ssl_context
*
,
const
unsigned
char
*
,
size_t
),
void
*
p_sni
)
{
ssl
->
f_sni
=
f_sni
;
ssl
->
p_sni
=
p_sni
;
}
int
ssl_set_alpn_protocols
(
ntbtls_t
ssl
,
const
char
**
protos
)
{
size_t
cur_len
,
tot_len
;
const
char
**
p
;
/*
* "Empty strings MUST NOT be included and byte strings MUST NOT be
* truncated". Check lengths now rather than later.
*/
tot_len
=
0
;
for
(
p
=
protos
;
*
p
!=
NULL
;
p
++
)
{
cur_len
=
strlen
(
*
p
);
tot_len
+=
cur_len
;
if
(
cur_len
==
0
||
cur_len
>
255
||
tot_len
>
65535
)
return
(
POLARSSL_ERR_SSL_BAD_INPUT_DATA
);
}
ssl
->
alpn_list
=
protos
;
return
(
0
);
}
const
char
*
ssl_get_alpn_protocol
(
const
ntbtls_t
ssl
)
{
return
(
ssl
->
alpn_chosen
);
}
void
ssl_set_max_version
(
ntbtls_t
ssl
,
int
major
,
int
minor
)
{
if
(
major
>=
SSL_MIN_MAJOR_VERSION
&&
major
<=
SSL_MAX_MAJOR_VERSION
&&
minor
>=
SSL_MIN_MINOR_VERSION
&&
minor
<=
SSL_MAX_MINOR_VERSION
)
{
ssl
->
max_major_ver
=
major
;
ssl
->
max_minor_ver
=
minor
;
}
}
void
ssl_set_min_version
(
ntbtls_t
ssl
,
int
major
,
int
minor
)
{
if
(
major
>=
SSL_MIN_MAJOR_VERSION
&&
major
<=
SSL_MAX_MAJOR_VERSION
&&
minor
>=
SSL_MIN_MINOR_VERSION
&&
minor
<=
SSL_MAX_MINOR_VERSION
)
{
ssl
->
min_major_ver
=
major
;
ssl
->
min_minor_ver
=
minor
;
}
}
int
ssl_set_max_frag_len
(
ntbtls_t
ssl
,
unsigned
char
mfl_code
)
{
if
(
mfl_code
>=
SSL_MAX_FRAG_LEN_INVALID
||
mfl_code_to_length
[
mfl_code
]
>
SSL_MAX_CONTENT_LEN
)
{
return
(
POLARSSL_ERR_SSL_BAD_INPUT_DATA
);
}
ssl
->
mfl_code
=
mfl_code
;
return
(
0
);
}
int
ssl_set_truncated_hmac
(
ntbtls_t
ssl
,
int
truncate
)
{
if
(
!
ssl
->
is_client
)
return
(
POLARSSL_ERR_SSL_BAD_INPUT_DATA
);
ssl
->
trunc_hmac
=
truncate
;
return
0
;
}
void
ssl_set_renegotiation
(
ntbtls_t
ssl
,
int
renegotiation
)
{
ssl
->
disable_renegotiation
=
renegotiation
;
}
void
ssl_legacy_renegotiation
(
ntbtls_t
ssl
,
int
allow_legacy
)
{
ssl
->
allow_legacy_renegotiation
=
allow_legacy
;
}
void
ssl_set_renegotiation_enforced
(
ntbtls_t
ssl
,
int
max_records
)
{
ssl
->
renego_max_records
=
max_records
;
}
int
ssl_set_session_tickets
(
ntbtls_t
ssl
,
int
use_tickets
)
{
ssl
->
session_tickets
=
use_tickets
;
if
(
ssl
->
is_client
)
return
(
0
);
if
(
ssl
->
f_rng
==
NULL
)
return
(
POLARSSL_ERR_SSL_BAD_INPUT_DATA
);
return
(
ssl_ticket_keys_init
(
ssl
));
}
void
ssl_set_session_ticket_lifetime
(
ntbtls_t
ssl
,
int
lifetime
)
{
ssl
->
ticket_lifetime
=
lifetime
;
}
/*
* SSL get accessors
*/
size_t
ssl_get_bytes_avail
(
const
ntbtls_t
ssl
)
{
return
(
ssl
->
in_offt
==
NULL
?
0
:
ssl
->
in_msglen
);
}
int
ssl_get_verify_result
(
const
ntbtls_t
ssl
)
{
return
(
ssl
->
session
->
verify_result
);
}
const
char
*
ssl_get_ciphersuite
(
const
ntbtls_t
ssl
)
{
if
(
ssl
==
NULL
||
ssl
->
session
==
NULL
)
return
(
NULL
);
return
ssl_get_ciphersuite_name
(
ssl
->
session
->
ciphersuite
);
}
const
char
*
ssl_get_version
(
const
ntbtls_t
ssl
)
{
switch
(
ssl
->
minor_ver
)
{
case
SSL_MINOR_VERSION_0
:
return
(
"SSLv3.0"
);
case
SSL_MINOR_VERSION_1
:
return
(
"TLSv1.0"
);
case
SSL_MINOR_VERSION_2
:
return
(
"TLSv1.1"
);
case
SSL_MINOR_VERSION_3
:
return
(
"TLSv1.2"
);
default
:
break
;
}
return
(
"unknown"
);
}
const
x509_crt
*
ssl_get_peer_cert
(
const
ntbtls_t
ssl
)
{
if
(
ssl
==
NULL
||
ssl
->
session
==
NULL
)
return
(
NULL
);
return
(
ssl
->
session
->
peer_cert
);
}
int
ssl_get_session
(
const
ntbtls_t
ssl
,
session_t
dst
)
{
if
(
ssl
==
NULL
||
dst
==
NULL
||
ssl
->
session
==
NULL
||
!
ssl
->
is_client
)
{
return
(
POLARSSL_ERR_SSL_BAD_INPUT_DATA
);
}
return
(
ssl_session_copy
(
dst
,
ssl
->
session
));
}
/*
* Perform a single step of the SSL handshake
*/
static
gpg_error_t
handshake_step
(
ntbtls_t
tls
)
{
gpg_error_t
err
;
if
(
tls
->
is_client
)
err
=
_ntbtls_handshake_client_step
(
ssl
);
else
err
=
_ntbtls_handshake_server_step
(
ssl
);
return
err
;
}
/*
* Perform the SSL handshake
*/
gpg_error_t
_ntbtls_handshake
(
ntbtls_t
tls
)
{
gpg_error_t
err
=
0
;
debug_msg
(
2
,
"=> handshake"
);
while
(
tls
->
state
!=
TLS_HANDSHAKE_OVER
)
{
err
=
handshake_step
(
tls
);
if
(
err
)
break
;
}
debug_msg
(
2
,
"<= handshake"
);
return
err
;
}
/*
* Write HelloRequest to request renegotiation on server
*/
static
int
ssl_write_hello_request
(
ntbtls_t
ssl
)
{
int
ret
;
debug_msg
(
2
,
"=> write hello request"
);
ssl
->
out_msglen
=
4
;
ssl
->
out_msgtype
=
TLS_MSG_HANDSHAKE
;
ssl
->
out_msg
[
0
]
=
TLS_HS_HELLO_REQUEST
;
if
((
ret
=
ssl_write_record
(
ssl
))
!=
0
)
{
SSL_DEBUG_RET
(
1
,
"ssl_write_record"
,
ret
);
return
(
ret
);
}
ssl
->
renegotiation
=
TLS_RENEGOTIATION_PENDING
;
debug_msg
(
2
,
"<= write hello request"
);
return
(
0
);
}
/*
* Actually renegotiate current connection, triggered by either:
* - calling ssl_renegotiate() on client,
* - receiving a HelloRequest on client during ssl_read(),
* - receiving any handshake message on server during ssl_read() after the
* initial handshake is completed
* If the handshake doesn't complete due to waiting for I/O, it will continue
* during the next calls to ssl_renegotiate() or ssl_read() respectively.
*/
static
int
ssl_start_renegotiation
(
ntbtls_t
ssl
)
{
int
ret
;
debug_msg
(
2
,
"=> renegotiate"
);
if
((
ret
=
handshake_init
(
ssl
))
!=
0
)
return
(
ret
);
ssl
->
state
=
TLS_HELLO_REQUEST
;
ssl
->
renegotiation
=
TLS_RENEGOTIATION
;
if
((
ret
=
ssl_handshake
(
ssl
))
!=
0
)
{
SSL_DEBUG_RET
(
1
,
"ssl_handshake"
,
ret
);
return
(
ret
);
}
debug_msg
(
2
,
"<= renegotiate"
);
return
(
0
);
}
/*
* Renegotiate current connection on client,
* or request renegotiation on server
*/
int
ssl_renegotiate
(
ntbtls_t
ssl
)
{
int
ret
=
POLARSSL_ERR_SSL_FEATURE_UNAVAILABLE
;
/* On server, just send the request */
if
(
!
tls
->
is_client
)
{
if
(
ssl
->
state
!=
TLS_HANDSHAKE_OVER
)
return
(
POLARSSL_ERR_SSL_BAD_INPUT_DATA
);
return
(
ssl_write_hello_request
(
ssl
));
}
/*
* On client, either start the renegotiation process or,
* if already in progress, continue the handshake
*/
if
(
ssl
->
renegotiation
!=
TLS_RENEGOTIATION
)
{
if
(
ssl
->
state
!=
SSL_HANDSHAKE_OVER
)
return
(
POLARSSL_ERR_SSL_BAD_INPUT_DATA
);
if
((
ret
=
ssl_start_renegotiation
(
ssl
))
!=
0
)
{
SSL_DEBUG_RET
(
1
,
"ssl_start_renegotiation"
,
ret
);
return
(
ret
);
}
}
else
{
if
((
ret
=
ssl_handshake
(
ssl
))
!=
0
)
{
SSL_DEBUG_RET
(
1
,
"ssl_handshake"
,
ret
);
return
(
ret
);
}
}
return
(
ret
);
}
/*
* Receive application data decrypted from the SSL layer
*/
int
ssl_read
(
ntbtls_t
ssl
,
unsigned
char
*
buf
,
size_t
len
)
{
int
ret
;
size_t
n
;
debug_msg
(
2
,
"=> read"
);
if
(
ssl
->
state
!=
SSL_HANDSHAKE_OVER
)
{
if
((
ret
=
ssl_handshake
(
ssl
))
!=
0
)
{
SSL_DEBUG_RET
(
1
,
"ssl_handshake"
,
ret
);
return
(
ret
);
}
}
if
(
ssl
->
in_offt
==
NULL
)
{
if
((
ret
=
ssl_read_record
(
ssl
))
!=
0
)
{
if
(
ret
==
POLARSSL_ERR_SSL_CONN_EOF
)
return
(
0
);
SSL_DEBUG_RET
(
1
,
"ssl_read_record"
,
ret
);
return
(
ret
);
}
if
(
ssl
->
in_msglen
==
0
&&
ssl
->
in_msgtype
==
TLS_MSG_APPLICATION_DATA
)
{
/*
* OpenSSL sends empty messages to randomize the IV
*/
if
((
ret
=
ssl_read_record
(
ssl
))
!=
0
)
{
if
(
ret
==
POLARSSL_ERR_SSL_CONN_EOF
)
return
(
0
);
SSL_DEBUG_RET
(
1
,
"ssl_read_record"
,
ret
);
return
(
ret
);
}
}
if
(
ssl
->
in_msgtype
==
TLS_MSG_HANDSHAKE
)
{
debug_msg
(
1
,
"received handshake message"
);
if
(
tls
->
is_client
&&
(
ssl
->
in_msg
[
0
]
!=
TLS_HS_HELLO_REQUEST
||
ssl
->
in_hslen
!=
4
))
{
debug_msg
(
1
,
"handshake received (not HelloRequest)"
);
return
(
POLARSSL_ERR_SSL_UNEXPECTED_MESSAGE
);
}
if
(
ssl
->
disable_renegotiation
==
TLS_RENEGOTIATION_DISABLED
||
(
ssl
->
secure_renegotiation
==
TLS_LEGACY_RENEGOTIATION
&&
ssl
->
allow_legacy_renegotiation
==
TLS_LEGACY_NO_RENEGOTIATION
))
{
debug_msg
(
3
,
"ignoring renegotiation, sending alert"
);
if
(
ssl
->
minor_ver
>=
SSL_MINOR_VERSION_1
)
{
if
((
ret
=
ssl_send_alert_message
(
ssl
,
TLS_ALERT_LEVEL_WARNING
,
TLS_ALERT_MSG_NO_RENEGOTIATION
))
!=
0
)
{
return
(
ret
);
}
}
else
{
debug_bug
();
return
(
POLARSSL_ERR_SSL_INTERNAL_ERROR
);
}
}
else
{
if
((
ret
=
ssl_start_renegotiation
(
ssl
))
!=
0
)
{
SSL_DEBUG_RET
(
1
,
"ssl_start_renegotiation"
,
ret
);
return
(
ret
);
}
return
(
POLARSSL_ERR_NET_WANT_READ
);
}
}
else
if
(
ssl
->
renegotiation
==
TLS_RENEGOTIATION_PENDING
)
{
ssl
->
renego_records_seen
++
;
if
(
ssl
->
renego_max_records
>=
0
&&
ssl
->
renego_records_seen
>
ssl
->
renego_max_records
)
{
debug_msg
(
1
,
"renegotiation requested, "
"but not honored by client"
);
return
(
POLARSSL_ERR_SSL_UNEXPECTED_MESSAGE
);
}
}
else
if
(
ssl
->
in_msgtype
!=
TLS_MSG_APPLICATION_DATA
)
{
debug_msg
(
1
,
"bad application data message"
);
return
(
POLARSSL_ERR_SSL_UNEXPECTED_MESSAGE
);
}
ssl
->
in_offt
=
ssl
->
in_msg
;
}
n
=
(
len
<
ssl
->
in_msglen
)
?
len
:
ssl
->
in_msglen
;
memcpy
(
buf
,
ssl
->
in_offt
,
n
);
ssl
->
in_msglen
-=
n
;
if
(
ssl
->
in_msglen
==
0
)
/* all bytes consumed */
ssl
->
in_offt
=
NULL
;
else
/* more data available */
ssl
->
in_offt
+=
n
;
debug_msg
(
2
,
"<= read"
);
return
((
int
)
n
);
}
/*
* Send application data to be encrypted by the SSL layer
*/
int
ssl_write
(
ntbtls_t
ssl
,
const
unsigned
char
*
buf
,
size_t
len
)
{
int
ret
;
size_t
n
;
unsigned
int
max_len
=
SSL_MAX_CONTENT_LEN
;
debug_msg
(
2
,
"=> write"
);
if
(
ssl
->
state
!=
SSL_HANDSHAKE_OVER
)
{
if
((
ret
=
ssl_handshake
(
ssl
))
!=
0
)
{
SSL_DEBUG_RET
(
1
,
"ssl_handshake"
,
ret
);
return
(
ret
);
}
}
/*
* Assume mfl_code is correct since it was checked when set
*/
max_len
=
mfl_code_to_length
[
ssl
->
mfl_code
];
/*
* Check if a smaller max length was negotiated
*/
if
(
ssl
->
session_out
!=
NULL
&&
mfl_code_to_length
[
ssl
->
session_out
->
mfl_code
]
<
max_len
)
{
max_len
=
mfl_code_to_length
[
ssl
->
session_out
->
mfl_code
];
}
n
=
(
len
<
max_len
)
?
len
:
max_len
;
if
(
ssl
->
out_left
!=
0
)
{
err
=
_ntbtls_flush_output
(
tls
);
if
(
err
)
{
SSL_DEBUG_RET
(
1
,
"ssl_flush_output"
,
err
);
return
err
;
}
}
else
{
ssl
->
out_msglen
=
n
;
ssl
->
out_msgtype
=
TLS_MSG_APPLICATION_DATA
;
memcpy
(
ssl
->
out_msg
,
buf
,
n
);
if
((
ret
=
ssl_write_record
(
ssl
))
!=
0
)
{
SSL_DEBUG_RET
(
1
,
"ssl_write_record"
,
ret
);
return
(
ret
);
}
}
debug_msg
(
2
,
"<= write"
);
return
((
int
)
n
);
}
/*
* Notify the peer that the connection is being closed
*/
int
ssl_close_notify
(
ntbtls_t
ssl
)
{
int
ret
;
debug_msg
(
2
,
"=> write close notify"
);
err
=
_ntbtls_flush_output
(
tls
);
if
(
err
)
{
SSL_DEBUG_RET
(
1
,
"ssl_flush_output"
,
ret
);
return
(
ret
);
}
if
(
ssl
->
state
==
SSL_HANDSHAKE_OVER
)
{
if
((
ret
=
ssl_send_alert_message
(
ssl
,
TLS_ALERT_LEVEL_WARNING
,
TLS_ALERT_MSG_CLOSE_NOTIFY
))
!=
0
)
{
return
(
ret
);
}
}
debug_msg
(
2
,
"<= write close notify"
);
return
(
ret
);
}
static
void
transform_free
(
ssl_transform
*
transform
)
{
if
(
!
transform
)
return
;
deflateEnd
(
&
transform
->
ctx_deflate
);
inflateEnd
(
&
transform
->
ctx_inflate
);
cipher_free
(
&
transform
->
cipher_ctx_enc
);
cipher_free
(
&
transform
->
cipher_ctx_dec
);
md_free
(
&
transform
->
md_ctx_enc
);
md_free
(
&
transform
->
md_ctx_dec
);
wipememory
(
transform
,
sizeof
(
ssl_transform
));
}
static
void
ssl_key_cert_free
(
ssl_key_cert
*
key_cert
)
{
ssl_key_cert
*
cur
=
key_cert
,
*
next
;
while
(
cur
!=
NULL
)
{
next
=
cur
->
next
;
if
(
cur
->
key_own_alloc
)
{
pk_free
(
cur
->
key
);
polarssl_free
(
cur
->
key
);
}
polarssl_free
(
cur
);
cur
=
next
;
}
}
static
void
handshake_free
(
ssl_handshake_params
*
handshake
)
{
if
(
!
handshake
)
return
;
dhm_free
(
&
handshake
->
dhm_ctx
);
ecdh_free
(
&
handshake
->
ecdh_ctx
);
/* explicit void pointer cast for buggy MS compiler */
polarssl_free
((
void
*
)
handshake
->
curves
);
/*
* Free only the linked list wrapper, not the keys themselves
* since the belong to the SNI callback
*/
if
(
handshake
->
sni_key_cert
!=
NULL
)
{
ssl_key_cert
*
cur
=
handshake
->
sni_key_cert
,
*
next
;
while
(
cur
!=
NULL
)
{
next
=
cur
->
next
;
polarssl_free
(
cur
);
cur
=
next
;
}
}
wipememory
(
handshake
,
sizeof
(
ssl_handshake_params
));
}
static
void
session_free
(
session_t
session
)
{
if
(
!
session
)
return
;
if
(
session
->
peer_cert
!=
NULL
)
{
x509_crt_free
(
session
->
peer_cert
);
polarssl_free
(
session
->
peer_cert
);
}
polarssl_free
(
session
->
ticket
);
wipememory
(
session
,
sizeof
*
session
);
}
/*
* Free an SSL context
*/
void
ssl_free
(
ntbtls_t
ssl
)
{
if
(
ssl
==
NULL
)
return
;
debug_msg
(
2
,
"=> free"
);
if
(
ssl
->
out_ctr
!=
NULL
)
{
wipememory
(
ssl
->
out_ctr
,
SSL_BUFFER_LEN
);
polarssl_free
(
ssl
->
out_ctr
);
}
if
(
ssl
->
in_ctr
!=
NULL
)
{
wipememory
(
ssl
->
in_ctr
,
SSL_BUFFER_LEN
);
polarssl_free
(
ssl
->
in_ctr
);
}
if
(
ssl
->
compress_buf
!=
NULL
)
{
wipememory
(
ssl
->
compress_buf
,
SSL_BUFFER_LEN
);
polarssl_free
(
ssl
->
compress_buf
);
}
mpi_free
(
&
ssl
->
dhm_P
);
mpi_free
(
&
ssl
->
dhm_G
);
if
(
ssl
->
transform
)
{
ssl_transform_free
(
ssl
->
transform
);
polarssl_free
(
ssl
->
transform
);
}
if
(
ssl
->
handshake
)
{
ssl_handshake_free
(
ssl
->
handshake
);
ssl_transform_free
(
ssl
->
transform_negotiate
);
session_free
(
ssl
->
session_negotiate
);
polarssl_free
(
ssl
->
handshake
);
polarssl_free
(
ssl
->
transform_negotiate
);
polarssl_free
(
ssl
->
session_negotiate
);
}
if
(
ssl
->
session
)
{
session_free
(
ssl
->
session
);
polarssl_free
(
ssl
->
session
);
}
if
(
ssl
->
ticket_keys
)
{
ssl_ticket_keys_free
(
ssl
->
ticket_keys
);
polarssl_free
(
ssl
->
ticket_keys
);
}
if
(
ssl
->
hostname
!=
NULL
)
{
wipememory
(
ssl
->
hostname
,
ssl
->
hostname_len
);
polarssl_free
(
ssl
->
hostname
);
ssl
->
hostname_len
=
0
;
}
if
(
ssl
->
psk
!=
NULL
)
{
wipememory
(
ssl
->
psk
,
ssl
->
psk_len
);
wipememory
(
ssl
->
psk_identity
,
ssl
->
psk_identity_len
);
polarssl_free
(
ssl
->
psk
);
polarssl_free
(
ssl
->
psk_identity
);
ssl
->
psk_len
=
0
;
ssl
->
psk_identity_len
=
0
;
}
ssl_key_cert_free
(
ssl
->
key_cert
);
debug_msg
(
2
,
"<= free"
);
/* Actually clear after last debug message */
wipememory
(
ssl
,
sizeof
(
ssl_context
));
}
/*
* Map gcrypt algo number to TLS algo number, return ANON if the algo
* is not supported.
*/
//FIXME:
// unsigned char
// ssl_sig_from_pk (pk_context * pk)
// {
// if (pk_can_do (pk, POLARSSL_PK_RSA))
// return (SSL_SIG_RSA);
// #endif
// #if defined(POLARSSL_ECDSA_C)
// if (pk_can_do (pk, POLARSSL_PK_ECDSA))
// return (SSL_SIG_ECDSA);
// #endif
// return (SSL_SIG_ANON);
// }
/*
* Map TLS signature algorithm number to a gcrypt algo number.
*/
pk_type_t
_ntbtls_pk_alg_from_sig
(
unsigned
char
sig
)
{
switch
(
sig
)
{
case
TLS_SIG_ANON
:
return
0
;
case
TLS_SIG_RSA
:
return
GCRY_PK_RSA
;
case
TLS_SIG_ECDSA
:
return
GCRY_PK_ECC
;
}
return
0
;
}
/*
* Map TLS hash algorithm number to a gcrypt algo number.
*/
md_algo_t
_ntbtls_md_alg_from_hash
(
unsigned
char
hash
)
{
switch
(
hash
)
{
case
TLS_HASH_SHA1
:
return
GCRY_MD_SHA1
;
case
TLS_HASH_SHA224
:
return
GCRY_MD_SHA224
;
case
TLS_HASH_SHA256
:
return
GCRY_MD_SHA256
;
case
TLS_HASH_SHA384
:
return
GCRY_MD_SHA384
;
case
TLS_HASH_SHA512
:
return
GCRY_MD_SHA512
;
}
return
0
;
}
/*
* Check is a curve proposed by the peer is in our list.
* Return 1 if we're willing to use it, 0 otherwise.
*/
int
ssl_curve_is_acceptable
(
const
ntbtls_t
ssl
,
ecp_group_id
grp_id
)
{
const
ecp_group_id
*
gid
;
for
(
gid
=
ssl
->
curve_list
;
*
gid
!=
POLARSSL_ECP_DP_NONE
;
gid
++
)
if
(
*
gid
==
grp_id
)
return
(
1
);
return
(
0
);
}
int
ssl_check_cert_usage
(
const
x509_crt
*
cert
,
const
ssl_ciphersuite_t
*
ciphersuite
,
int
is_client
)
{
int
usage
=
0
;
const
char
*
ext_oid
;
size_t
ext_len
;
if
(
!
is_client
)
{
/* Server part of the key exchange */
switch
(
ciphersuite
->
key_exchange
)
{
case
POLARSSL_KEY_EXCHANGE_RSA
:
case
POLARSSL_KEY_EXCHANGE_RSA_PSK
:
usage
=
KU_KEY_ENCIPHERMENT
;
break
;
case
POLARSSL_KEY_EXCHANGE_DHE_RSA
:
case
POLARSSL_KEY_EXCHANGE_ECDHE_RSA
:
case
POLARSSL_KEY_EXCHANGE_ECDHE_ECDSA
:
usage
=
KU_DIGITAL_SIGNATURE
;
break
;
case
POLARSSL_KEY_EXCHANGE_ECDH_RSA
:
case
POLARSSL_KEY_EXCHANGE_ECDH_ECDSA
:
usage
=
KU_KEY_AGREEMENT
;
break
;
/* Don't use default: we want warnings when adding new values */
case
POLARSSL_KEY_EXCHANGE_NONE
:
case
POLARSSL_KEY_EXCHANGE_PSK
:
case
POLARSSL_KEY_EXCHANGE_DHE_PSK
:
case
POLARSSL_KEY_EXCHANGE_ECDHE_PSK
:
usage
=
0
;
break
;
}
}
else
{
/* Client auth: we only implement rsa_sign and ecdsa_sign for now */
usage
=
KU_DIGITAL_SIGNATURE
;
}
if
(
x509_crt_check_key_usage
(
cert
,
usage
)
!=
0
)
return
(
-1
);
if
(
!
is_client
)
{
ext_oid
=
OID_SERVER_AUTH
;
ext_len
=
OID_SIZE
(
OID_SERVER_AUTH
);
}
else
{
ext_oid
=
OID_CLIENT_AUTH
;
ext_len
=
OID_SIZE
(
OID_CLIENT_AUTH
);
}
if
(
x509_crt_check_extended_key_usage
(
cert
,
ext_oid
,
ext_len
)
!=
0
)
return
(
-1
);
return
(
0
);
}
File Metadata
Details
Attached
Mime Type
text/x-c
Expires
Sun, Feb 22, 6:42 PM (1 d, 12 h)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
ff/57/80c34dd1a0aeb84df13f227df115
Attached To
rT Not Too Bad TLS
Event Timeline
Log In to Comment