Initial import.
This commit is contained in:
commit
3210f38e04
292 changed files with 58526 additions and 0 deletions
71
src/ssl/prf.c
Normal file
71
src/ssl/prf.c
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "inner.h"
|
||||
|
||||
/* see inner.h */
|
||||
void
|
||||
br_tls_phash(void *dst, size_t len,
|
||||
const br_hash_class *dig,
|
||||
const void *secret, size_t secret_len,
|
||||
const char *label, const void *seed, size_t seed_len)
|
||||
{
|
||||
unsigned char *buf;
|
||||
unsigned char tmp[64], a[64];
|
||||
br_hmac_key_context kc;
|
||||
br_hmac_context hc;
|
||||
size_t label_len, hlen;
|
||||
|
||||
if (len == 0) {
|
||||
return;
|
||||
}
|
||||
buf = dst;
|
||||
for (label_len = 0; label[label_len]; label_len ++);
|
||||
hlen = br_digest_size(dig);
|
||||
br_hmac_key_init(&kc, dig, secret, secret_len);
|
||||
br_hmac_init(&hc, &kc, 0);
|
||||
br_hmac_update(&hc, label, label_len);
|
||||
br_hmac_update(&hc, seed, seed_len);
|
||||
br_hmac_out(&hc, a);
|
||||
for (;;) {
|
||||
size_t u;
|
||||
|
||||
br_hmac_init(&hc, &kc, 0);
|
||||
br_hmac_update(&hc, a, hlen);
|
||||
br_hmac_update(&hc, label, label_len);
|
||||
br_hmac_update(&hc, seed, seed_len);
|
||||
br_hmac_out(&hc, tmp);
|
||||
for (u = 0; u < hlen && u < len; u ++) {
|
||||
buf[u] ^= tmp[u];
|
||||
}
|
||||
buf += u;
|
||||
len -= u;
|
||||
if (len == 0) {
|
||||
return;
|
||||
}
|
||||
br_hmac_init(&hc, &kc, 0);
|
||||
br_hmac_update(&hc, a, hlen);
|
||||
br_hmac_out(&hc, a);
|
||||
}
|
||||
}
|
||||
43
src/ssl/prf_md5sha1.c
Normal file
43
src/ssl/prf_md5sha1.c
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "inner.h"
|
||||
|
||||
/* see bearssl.h */
|
||||
void
|
||||
br_tls10_prf(void *dst, size_t len,
|
||||
const void *secret, size_t secret_len,
|
||||
const char *label, const void *seed, size_t seed_len)
|
||||
{
|
||||
const unsigned char *s1;
|
||||
size_t slen;
|
||||
|
||||
s1 = secret;
|
||||
slen = (secret_len + 1) >> 1;
|
||||
memset(dst, 0, len);
|
||||
br_tls_phash(dst, len, &br_md5_vtable,
|
||||
s1, slen, label, seed, seed_len);
|
||||
br_tls_phash(dst, len, &br_sha1_vtable,
|
||||
s1 + secret_len - slen, slen, label, seed, seed_len);
|
||||
}
|
||||
36
src/ssl/prf_sha256.c
Normal file
36
src/ssl/prf_sha256.c
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "inner.h"
|
||||
|
||||
/* see bearssl.h */
|
||||
void
|
||||
br_tls12_sha256_prf(void *dst, size_t len,
|
||||
const void *secret, size_t secret_len,
|
||||
const char *label, const void *seed, size_t seed_len)
|
||||
{
|
||||
memset(dst, 0, len);
|
||||
br_tls_phash(dst, len, &br_sha256_vtable,
|
||||
secret, secret_len, label, seed, seed_len);
|
||||
}
|
||||
36
src/ssl/prf_sha384.c
Normal file
36
src/ssl/prf_sha384.c
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "inner.h"
|
||||
|
||||
/* see bearssl.h */
|
||||
void
|
||||
br_tls12_sha384_prf(void *dst, size_t len,
|
||||
const void *secret, size_t secret_len,
|
||||
const char *label, const void *seed, size_t seed_len)
|
||||
{
|
||||
memset(dst, 0, len);
|
||||
br_tls_phash(dst, len, &br_sha384_vtable,
|
||||
secret, secret_len, label, seed, seed_len);
|
||||
}
|
||||
78
src/ssl/ssl_client.c
Normal file
78
src/ssl/ssl_client.c
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "inner.h"
|
||||
|
||||
/* see bearssl_ssl.h */
|
||||
void
|
||||
br_ssl_client_zero(br_ssl_client_context *cc)
|
||||
{
|
||||
/*
|
||||
* For really standard C, we should explicitly set to NULL all
|
||||
* pointers, and 0 all other fields. However, on all our target
|
||||
* architectures, a direct memset() will work, be faster, and
|
||||
* use a lot less code.
|
||||
*/
|
||||
memset(cc, 0, sizeof *cc);
|
||||
}
|
||||
|
||||
/* see bearssl_ssl.h */
|
||||
int
|
||||
br_ssl_client_reset(br_ssl_client_context *cc,
|
||||
const char *server_name, int resume_session)
|
||||
{
|
||||
size_t n;
|
||||
|
||||
br_ssl_engine_set_buffer(&cc->eng, NULL, 0, 0);
|
||||
cc->eng.version_out = cc->eng.version_min;
|
||||
if (!resume_session) {
|
||||
br_ssl_client_forget_session(cc);
|
||||
}
|
||||
if (!br_ssl_engine_init_rand(&cc->eng)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* We always set back the "reneg" flag to 0 because we use it
|
||||
* to distinguish between first handshake and renegotiation.
|
||||
* Note that "renegotiation" and "session resumption" are two
|
||||
* different things.
|
||||
*/
|
||||
cc->eng.reneg = 0;
|
||||
|
||||
if (server_name == NULL) {
|
||||
cc->eng.server_name[0] = 0;
|
||||
} else {
|
||||
n = strlen(server_name) + 1;
|
||||
if (n > sizeof cc->eng.server_name) {
|
||||
br_ssl_engine_fail(&cc->eng, BR_ERR_BAD_PARAM);
|
||||
return 0;
|
||||
}
|
||||
memcpy(cc->eng.server_name, server_name, n);
|
||||
}
|
||||
|
||||
br_ssl_engine_hs_reset(&cc->eng,
|
||||
br_ssl_hs_client_init_main, br_ssl_hs_client_run);
|
||||
return br_ssl_engine_last_error(&cc->eng) == BR_ERR_OK;
|
||||
}
|
||||
194
src/ssl/ssl_client_full.c
Normal file
194
src/ssl/ssl_client_full.c
Normal file
|
|
@ -0,0 +1,194 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "inner.h"
|
||||
|
||||
/* see bearssl_ssl.h */
|
||||
void
|
||||
br_ssl_client_init_full(br_ssl_client_context *cc,
|
||||
br_x509_minimal_context *xc,
|
||||
const br_x509_trust_anchor *trust_anchors, size_t trust_anchors_num)
|
||||
{
|
||||
/*
|
||||
* The "full" profile supports all implemented cipher suites.
|
||||
*
|
||||
* Rationale for suite order, from most important to least
|
||||
* important rule:
|
||||
*
|
||||
* -- Don't use 3DES if AES is available.
|
||||
* -- Try to have Forward Secrecy (ECDHE suite) if possible.
|
||||
* -- When not using Forward Secrecy, ECDH key exchange is
|
||||
* better than RSA key exchange (slightly more expensive on the
|
||||
* client, but much cheaper on the server, and it implies smaller
|
||||
* messages).
|
||||
* -- GCM is better than CBC.
|
||||
* -- AES-128 is preferred over AES-256 (AES-128 is already
|
||||
* strong enough, and AES-256 is 40% more expensive).
|
||||
*/
|
||||
static const uint16_t suites[] = {
|
||||
BR_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
|
||||
BR_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
|
||||
BR_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
|
||||
BR_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
|
||||
BR_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
|
||||
BR_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
|
||||
BR_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,
|
||||
BR_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,
|
||||
BR_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
|
||||
BR_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
|
||||
BR_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
|
||||
BR_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
|
||||
BR_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256,
|
||||
BR_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256,
|
||||
BR_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384,
|
||||
BR_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384,
|
||||
BR_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256,
|
||||
BR_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256,
|
||||
BR_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384,
|
||||
BR_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384,
|
||||
BR_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,
|
||||
BR_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA,
|
||||
BR_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA,
|
||||
BR_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA,
|
||||
BR_TLS_RSA_WITH_AES_128_GCM_SHA256,
|
||||
BR_TLS_RSA_WITH_AES_256_GCM_SHA384,
|
||||
BR_TLS_RSA_WITH_AES_128_CBC_SHA256,
|
||||
BR_TLS_RSA_WITH_AES_256_CBC_SHA256,
|
||||
BR_TLS_RSA_WITH_AES_128_CBC_SHA,
|
||||
BR_TLS_RSA_WITH_AES_256_CBC_SHA,
|
||||
BR_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
|
||||
BR_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
|
||||
BR_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA,
|
||||
BR_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA,
|
||||
BR_TLS_RSA_WITH_3DES_EDE_CBC_SHA
|
||||
};
|
||||
|
||||
/*
|
||||
* All hash functions are activated.
|
||||
* Note: the X.509 validation engine will nonetheless refuse to
|
||||
* validate signatures that use MD5 as hash function.
|
||||
*/
|
||||
static const br_hash_class *hashes[] = {
|
||||
&br_md5_vtable,
|
||||
&br_sha1_vtable,
|
||||
&br_sha224_vtable,
|
||||
&br_sha256_vtable,
|
||||
&br_sha384_vtable,
|
||||
&br_sha512_vtable
|
||||
};
|
||||
|
||||
int id;
|
||||
|
||||
/*
|
||||
* Reset client context and set supported versions from TLS-1.0
|
||||
* to TLS-1.2 (inclusive).
|
||||
*/
|
||||
br_ssl_client_zero(cc);
|
||||
br_ssl_engine_set_versions(&cc->eng, BR_TLS10, BR_TLS12);
|
||||
|
||||
/*
|
||||
* X.509 engine uses SHA-256 to hash certificate DN (for
|
||||
* comparisons).
|
||||
*/
|
||||
br_x509_minimal_init(xc, &br_sha256_vtable,
|
||||
trust_anchors, trust_anchors_num);
|
||||
|
||||
/*
|
||||
* Set suites and asymmetric crypto implementations. We use the
|
||||
* "i31" code for RSA (it is somewhat faster than the "i32"
|
||||
* implementation).
|
||||
* TODO: change that when better implementations are made available.
|
||||
*/
|
||||
br_ssl_engine_set_suites(&cc->eng, suites,
|
||||
(sizeof suites) / (sizeof suites[0]));
|
||||
br_ssl_client_set_rsapub(cc, &br_rsa_i31_public);
|
||||
br_ssl_client_set_rsavrfy(cc, &br_rsa_i31_pkcs1_vrfy);
|
||||
br_ssl_engine_set_ec(&cc->eng, &br_ec_prime_i31);
|
||||
br_ssl_client_set_ecdsa(cc, &br_ecdsa_i31_vrfy_asn1);
|
||||
br_x509_minimal_set_rsa(xc, &br_rsa_i31_pkcs1_vrfy);
|
||||
br_x509_minimal_set_ecdsa(xc,
|
||||
&br_ec_prime_i31, &br_ecdsa_i31_vrfy_asn1);
|
||||
|
||||
/*
|
||||
* Set supported hash functions, for the SSL engine and for the
|
||||
* X.509 engine.
|
||||
*/
|
||||
for (id = br_md5_ID; id <= br_sha512_ID; id ++) {
|
||||
const br_hash_class *hc;
|
||||
|
||||
hc = hashes[id - 1];
|
||||
br_ssl_engine_set_hash(&cc->eng, id, hc);
|
||||
br_x509_minimal_set_hash(xc, id, hc);
|
||||
}
|
||||
|
||||
/*
|
||||
* Link the X.509 engine in the SSL engine.
|
||||
*/
|
||||
br_ssl_engine_set_x509(&cc->eng, &xc->vtable);
|
||||
|
||||
/*
|
||||
* Set the PRF implementations.
|
||||
*/
|
||||
br_ssl_engine_set_prf10(&cc->eng, &br_tls10_prf);
|
||||
br_ssl_engine_set_prf_sha256(&cc->eng, &br_tls12_sha256_prf);
|
||||
br_ssl_engine_set_prf_sha384(&cc->eng, &br_tls12_sha384_prf);
|
||||
|
||||
/*
|
||||
* Symmetric encryption. We use the "constant-time"
|
||||
* implementations, which are the safest.
|
||||
*
|
||||
* On architectures detected as "64-bit", use the 64-bit
|
||||
* versions (aes_ct64, ghash_ctmul64).
|
||||
*/
|
||||
#if BR_64
|
||||
br_ssl_engine_set_aes_cbc(&cc->eng,
|
||||
&br_aes_ct64_cbcenc_vtable,
|
||||
&br_aes_ct64_cbcdec_vtable);
|
||||
br_ssl_engine_set_aes_ctr(&cc->eng,
|
||||
&br_aes_ct64_ctr_vtable);
|
||||
br_ssl_engine_set_ghash(&cc->eng,
|
||||
&br_ghash_ctmul64);
|
||||
#else
|
||||
br_ssl_engine_set_aes_cbc(&cc->eng,
|
||||
&br_aes_ct_cbcenc_vtable,
|
||||
&br_aes_ct_cbcdec_vtable);
|
||||
br_ssl_engine_set_aes_ctr(&cc->eng,
|
||||
&br_aes_ct_ctr_vtable);
|
||||
br_ssl_engine_set_ghash(&cc->eng,
|
||||
&br_ghash_ctmul);
|
||||
#endif
|
||||
br_ssl_engine_set_des_cbc(&cc->eng,
|
||||
&br_des_ct_cbcenc_vtable,
|
||||
&br_des_ct_cbcdec_vtable);
|
||||
|
||||
/*
|
||||
* Set the SSL record engines (CBC, GCM).
|
||||
*/
|
||||
br_ssl_engine_set_cbc(&cc->eng,
|
||||
&br_sslrec_in_cbc_vtable,
|
||||
&br_sslrec_out_cbc_vtable);
|
||||
br_ssl_engine_set_gcm(&cc->eng,
|
||||
&br_sslrec_in_gcm_vtable,
|
||||
&br_sslrec_out_gcm_vtable);
|
||||
}
|
||||
1468
src/ssl/ssl_engine.c
Normal file
1468
src/ssl/ssl_engine.c
Normal file
File diff suppressed because it is too large
Load diff
46
src/ssl/ssl_hashes.c
Normal file
46
src/ssl/ssl_hashes.c
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "inner.h"
|
||||
|
||||
/* see inner.h */
|
||||
int
|
||||
br_ssl_choose_hash(unsigned bf)
|
||||
{
|
||||
static const unsigned char pref[] = {
|
||||
br_sha256_ID, br_sha384_ID, br_sha512_ID,
|
||||
br_sha224_ID, br_sha1_ID
|
||||
};
|
||||
size_t u;
|
||||
|
||||
for (u = 0; u < sizeof pref; u ++) {
|
||||
int x;
|
||||
|
||||
x = pref[u];
|
||||
if ((bf >> x) & 1) {
|
||||
return x;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
1473
src/ssl/ssl_hs_client.c
Normal file
1473
src/ssl/ssl_hs_client.c
Normal file
File diff suppressed because it is too large
Load diff
992
src/ssl/ssl_hs_client.t0
Normal file
992
src/ssl/ssl_hs_client.t0
Normal file
|
|
@ -0,0 +1,992 @@
|
|||
\ Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
|
||||
\
|
||||
\ Permission is hereby granted, free of charge, to any person obtaining
|
||||
\ a copy of this software and associated documentation files (the
|
||||
\ "Software"), to deal in the Software without restriction, including
|
||||
\ without limitation the rights to use, copy, modify, merge, publish,
|
||||
\ distribute, sublicense, and/or sell copies of the Software, and to
|
||||
\ permit persons to whom the Software is furnished to do so, subject to
|
||||
\ the following conditions:
|
||||
\
|
||||
\ The above copyright notice and this permission notice shall be
|
||||
\ included in all copies or substantial portions of the Software.
|
||||
\
|
||||
\ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
\ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
\ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
\ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
\ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
\ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
\ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
\ SOFTWARE.
|
||||
|
||||
\ ----------------------------------------------------------------------
|
||||
\ Handshake processing code, for the client.
|
||||
\ The common T0 code (ssl_hs_common.t0) shall be read first.
|
||||
|
||||
preamble {
|
||||
|
||||
/*
|
||||
* This macro evaluates to a pointer to the client context, under that
|
||||
* specific name. It must be noted that since the engine context is the
|
||||
* first field of the br_ssl_client_context structure ('eng'), then
|
||||
* pointers values of both types are interchangeable, modulo an
|
||||
* appropriate cast. This also means that "adresses" computed as offsets
|
||||
* within the structure work for both kinds of context.
|
||||
*/
|
||||
#define CTX ((br_ssl_client_context *)ENG)
|
||||
|
||||
/*
|
||||
* Generate the pre-master secret for RSA key exchange, and encrypt it
|
||||
* with the server's public key. Returned value is either the encrypted
|
||||
* data length (in bytes), or -x on error, with 'x' being an error code.
|
||||
*
|
||||
* This code assumes that the public key has been already verified (it
|
||||
* was properly obtained by the X.509 engine, and it has the right type,
|
||||
* i.e. it is of type RSA and suitable for encryption).
|
||||
*/
|
||||
static int
|
||||
make_pms_rsa(br_ssl_client_context *ctx, int prf_id)
|
||||
{
|
||||
const br_x509_class **xc;
|
||||
const br_x509_pkey *pk;
|
||||
const unsigned char *n;
|
||||
unsigned char *pms;
|
||||
size_t nlen, u;
|
||||
|
||||
xc = ctx->eng.x509ctx;
|
||||
pk = (*xc)->get_pkey(xc);
|
||||
|
||||
/*
|
||||
* Compute actual RSA key length, in case there are leading zeros.
|
||||
*/
|
||||
n = pk->key.rsa.n;
|
||||
nlen = pk->key.rsa.nlen;
|
||||
while (nlen > 0 && *n == 0) {
|
||||
n ++;
|
||||
nlen --;
|
||||
}
|
||||
|
||||
/*
|
||||
* We need at least 59 bytes (48 bytes for pre-master secret, and
|
||||
* 11 bytes for the PKCS#1 type 2 padding). Note that the X.509
|
||||
* minimal engine normally blocks RSA keys shorter than 128 bytes,
|
||||
* so this is mostly for public keys provided explicitly by the
|
||||
* caller.
|
||||
*/
|
||||
if (nlen < 59) {
|
||||
return -BR_ERR_X509_WEAK_PUBLIC_KEY;
|
||||
}
|
||||
if (nlen > sizeof ctx->eng.pad) {
|
||||
return -BR_ERR_LIMIT_EXCEEDED;
|
||||
}
|
||||
|
||||
/*
|
||||
* Make PMS.
|
||||
*/
|
||||
pms = ctx->eng.pad + nlen - 48;
|
||||
br_enc16be(pms, ctx->eng.version_max);
|
||||
br_hmac_drbg_generate(&ctx->eng.rng, pms + 2, 46);
|
||||
br_ssl_engine_compute_master(&ctx->eng, prf_id, pms, 48);
|
||||
|
||||
/*
|
||||
* Apply PKCS#1 type 2 padding.
|
||||
*/
|
||||
ctx->eng.pad[0] = 0x00;
|
||||
ctx->eng.pad[1] = 0x02;
|
||||
ctx->eng.pad[nlen - 49] = 0x00;
|
||||
br_hmac_drbg_generate(&ctx->eng.rng, ctx->eng.pad + 2, nlen - 51);
|
||||
for (u = 2; u < nlen - 49; u ++) {
|
||||
while (ctx->eng.pad[u] == 0) {
|
||||
br_hmac_drbg_generate(&ctx->eng.rng,
|
||||
&ctx->eng.pad[u], 1);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Compute RSA encryption.
|
||||
*/
|
||||
if (!ctx->irsapub(ctx->eng.pad, nlen, &pk->key.rsa)) {
|
||||
return -BR_ERR_LIMIT_EXCEEDED;
|
||||
}
|
||||
return (int)nlen;
|
||||
}
|
||||
|
||||
/*
|
||||
* OID for hash functions in RSA signatures.
|
||||
*/
|
||||
static const unsigned char HASH_OID_SHA1[] = {
|
||||
0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A
|
||||
};
|
||||
|
||||
static const unsigned char HASH_OID_SHA224[] = {
|
||||
0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04
|
||||
};
|
||||
|
||||
static const unsigned char HASH_OID_SHA256[] = {
|
||||
0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01
|
||||
};
|
||||
|
||||
static const unsigned char HASH_OID_SHA384[] = {
|
||||
0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02
|
||||
};
|
||||
|
||||
static const unsigned char HASH_OID_SHA512[] = {
|
||||
0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03
|
||||
};
|
||||
|
||||
static const unsigned char *HASH_OID[] = {
|
||||
HASH_OID_SHA1,
|
||||
HASH_OID_SHA224,
|
||||
HASH_OID_SHA256,
|
||||
HASH_OID_SHA384,
|
||||
HASH_OID_SHA512
|
||||
};
|
||||
|
||||
/*
|
||||
* Check the RSA signature on the ServerKeyExchange message.
|
||||
* hash hash function ID (2 to 6), or 0 for MD5+SHA-1 (with RSA only)
|
||||
* use_rsa non-zero for RSA signature, zero for ECDSA
|
||||
* sig_len signature length (in bytes); signature value is in the pad
|
||||
* Returned value is 0 on success, or an error code.
|
||||
*/
|
||||
static int
|
||||
verify_SKE_sig(br_ssl_client_context *ctx,
|
||||
int hash, int use_rsa, size_t sig_len)
|
||||
{
|
||||
const br_x509_class **xc;
|
||||
const br_x509_pkey *pk;
|
||||
br_multihash_context mhc;
|
||||
unsigned char hv[64], head[4];
|
||||
size_t hv_len;
|
||||
|
||||
xc = ctx->eng.x509ctx;
|
||||
pk = (*xc)->get_pkey(xc);
|
||||
br_multihash_zero(&mhc);
|
||||
br_multihash_copyimpl(&mhc, &ctx->eng.mhash);
|
||||
br_multihash_init(&mhc);
|
||||
br_multihash_update(&mhc,
|
||||
ctx->eng.client_random, sizeof ctx->eng.client_random);
|
||||
br_multihash_update(&mhc,
|
||||
ctx->eng.server_random, sizeof ctx->eng.server_random);
|
||||
head[0] = 3;
|
||||
head[1] = 0;
|
||||
head[2] = ctx->eng.ecdhe_curve;
|
||||
head[3] = ctx->eng.ecdhe_point_len;
|
||||
br_multihash_update(&mhc, head, sizeof head);
|
||||
br_multihash_update(&mhc,
|
||||
ctx->eng.ecdhe_point, ctx->eng.ecdhe_point_len);
|
||||
if (hash) {
|
||||
hv_len = br_multihash_out(&mhc, hash, hv);
|
||||
if (hv_len == 0) {
|
||||
return BR_ERR_INVALID_ALGORITHM;
|
||||
}
|
||||
} else {
|
||||
if (!br_multihash_out(&mhc, br_md5_ID, hv)
|
||||
|| !br_multihash_out(&mhc, br_sha1_ID, hv + 16))
|
||||
{
|
||||
return BR_ERR_INVALID_ALGORITHM;
|
||||
}
|
||||
hv_len = 36;
|
||||
}
|
||||
if (use_rsa) {
|
||||
unsigned char tmp[64];
|
||||
const unsigned char *hash_oid;
|
||||
|
||||
if (hash) {
|
||||
hash_oid = HASH_OID[hash - 2];
|
||||
} else {
|
||||
hash_oid = NULL;
|
||||
}
|
||||
if (!ctx->irsavrfy(ctx->eng.pad, sig_len,
|
||||
hash_oid, hv_len, &pk->key.rsa, tmp)
|
||||
|| memcmp(tmp, hv, hv_len) != 0)
|
||||
{
|
||||
return BR_ERR_BAD_SIGNATURE;
|
||||
}
|
||||
} else {
|
||||
if (!ctx->iecdsa(ctx->eng.iec, hv, hv_len, &pk->key.ec,
|
||||
ctx->eng.pad, sig_len))
|
||||
{
|
||||
return BR_ERR_BAD_SIGNATURE;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform client-size ECDH (or ECDHE). The point that should be sent to
|
||||
* the server is written in the pad; returned value is either the point
|
||||
* length (in bytes), or -x on error, with 'x' being an error code.
|
||||
*
|
||||
* The point _from_ the server is taken from ecdhe_point[] if 'ecdhe'
|
||||
* is non-zero, or from the X.509 engine context if 'ecdhe' is zero
|
||||
* (for static ECDH).
|
||||
*/
|
||||
static int
|
||||
make_pms_ecdh(br_ssl_client_context *ctx, unsigned ecdhe, int prf_id)
|
||||
{
|
||||
int curve;
|
||||
unsigned char key[66], point[133];
|
||||
const unsigned char *generator, *order, *point_src;
|
||||
size_t glen, olen, point_len;
|
||||
unsigned char mask;
|
||||
|
||||
if (ecdhe) {
|
||||
curve = ctx->eng.ecdhe_curve;
|
||||
point_src = ctx->eng.ecdhe_point;
|
||||
point_len = ctx->eng.ecdhe_point_len;
|
||||
} else {
|
||||
const br_x509_class **xc;
|
||||
const br_x509_pkey *pk;
|
||||
|
||||
xc = ctx->eng.x509ctx;
|
||||
pk = (*xc)->get_pkey(xc);
|
||||
curve = pk->key.ec.curve;
|
||||
point_src = pk->key.ec.q;
|
||||
point_len = pk->key.ec.qlen;
|
||||
}
|
||||
if ((ctx->eng.iec->supported_curves & ((uint32_t)1 << curve)) == 0) {
|
||||
return -BR_ERR_INVALID_ALGORITHM;
|
||||
}
|
||||
|
||||
/*
|
||||
* We need to generate our key, as a non-zero random value which
|
||||
* is lower than the curve order, in a "large enough" range. We
|
||||
* force top bit to 0 and bottom bit to 1, which guarantees that
|
||||
* the value is in the proper range.
|
||||
*/
|
||||
order = ctx->eng.iec->order(curve, &olen);
|
||||
mask = 0xFF;
|
||||
while (mask >= order[0]) {
|
||||
mask >>= 1;
|
||||
}
|
||||
br_hmac_drbg_generate(&ctx->eng.rng, key, olen);
|
||||
key[0] &= mask;
|
||||
key[olen - 1] |= 0x01;
|
||||
|
||||
/*
|
||||
* Compute the common ECDH point, whose X coordinate is the
|
||||
* pre-master secret.
|
||||
*/
|
||||
generator = ctx->eng.iec->generator(curve, &glen);
|
||||
if (glen != point_len) {
|
||||
return -BR_ERR_INVALID_ALGORITHM;
|
||||
}
|
||||
|
||||
memcpy(point, point_src, glen);
|
||||
if (!ctx->eng.iec->mul(point, glen, key, olen, curve)) {
|
||||
return -BR_ERR_INVALID_ALGORITHM;
|
||||
}
|
||||
|
||||
/*
|
||||
* The pre-master secret is the X coordinate.
|
||||
*/
|
||||
br_ssl_engine_compute_master(&ctx->eng, prf_id, point + 1, glen >> 1);
|
||||
|
||||
memcpy(point, generator, glen);
|
||||
if (!ctx->eng.iec->mul(point, glen, key, olen, curve)) {
|
||||
return -BR_ERR_INVALID_ALGORITHM;
|
||||
}
|
||||
memcpy(ctx->eng.pad, point, glen);
|
||||
return (int)glen;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
\ =======================================================================
|
||||
|
||||
: addr-ctx:
|
||||
next-word { field }
|
||||
"addr-" field + 0 1 define-word
|
||||
0 8191 "offsetof(br_ssl_client_context, " field + ")" + make-CX
|
||||
postpone literal postpone ; ;
|
||||
|
||||
\ Length of the Secure Renegotiation extension. This is 5 for the
|
||||
\ first handshake, 17 for a renegotiation (if the server supports the
|
||||
\ extension), or 0 if we know that the server does not support the
|
||||
\ extension.
|
||||
: ext-reneg-length ( -- n )
|
||||
addr-reneg get8 dup if 1 - 17 * else drop 5 then ;
|
||||
|
||||
\ Length of SNI extension.
|
||||
: ext-sni-length ( -- len )
|
||||
addr-server_name strlen dup if 9 + then ;
|
||||
|
||||
\ Length of Maximum Fragment Length extension.
|
||||
: ext-frag-length ( -- len )
|
||||
addr-log_max_frag_len get8 14 = if 0 else 5 then ;
|
||||
|
||||
\ Test support for RSA signatures.
|
||||
cc: supports-rsa-sign? ( -- bool ) {
|
||||
T0_PUSHi(-(CTX->irsavrfy != 0));
|
||||
}
|
||||
|
||||
\ Test support for ECDSA signatures.
|
||||
cc: supports-ecdsa? ( -- bool ) {
|
||||
T0_PUSHi(-(CTX->iecdsa != 0));
|
||||
}
|
||||
|
||||
\ Length of Signatures extension.
|
||||
: ext-signatures-length ( -- len )
|
||||
supported-hash-functions { x } drop
|
||||
0
|
||||
supports-rsa-sign? if x + then
|
||||
supports-ecdsa? if x + then
|
||||
dup if 1 << 6 + then ;
|
||||
|
||||
\ Write supported hash functions ( sign -- )
|
||||
: write-hashes
|
||||
{ sign }
|
||||
supported-hash-functions drop
|
||||
\ We advertise hash functions in the following preference order:
|
||||
\ SHA-256 SHA-224 SHA-384 SHA-512 SHA-1
|
||||
\ Rationale:
|
||||
\ -- SHA-256 and SHA-224 are more efficient on 32-bit architectures
|
||||
\ -- SHA-1 is less than ideally collision-resistant
|
||||
dup 0x10 and if 4 write8 sign write8 then
|
||||
dup 0x08 and if 3 write8 sign write8 then
|
||||
dup 0x20 and if 5 write8 sign write8 then
|
||||
dup 0x40 and if 6 write8 sign write8 then
|
||||
0x04 and if 2 write8 sign write8 then ;
|
||||
|
||||
\ Length of Supported Curves extension.
|
||||
: ext-supported-curves-length ( -- len )
|
||||
supported-curves dup if
|
||||
0 { x }
|
||||
begin dup while
|
||||
dup 1 and x + >x
|
||||
1 >>
|
||||
repeat
|
||||
drop x 1 << 6 +
|
||||
then ;
|
||||
|
||||
\ Length of Supported Point Formats extension.
|
||||
: ext-point-format-length ( -- len )
|
||||
supported-curves if 6 else 0 then ;
|
||||
|
||||
\ Write handshake message: ClientHello
|
||||
: write-ClientHello ( -- )
|
||||
{ ; total-ext-length }
|
||||
|
||||
\ Compute length for extensions (without the general two-byte header)
|
||||
ext-reneg-length ext-sni-length + ext-frag-length +
|
||||
ext-signatures-length +
|
||||
ext-supported-curves-length + ext-point-format-length +
|
||||
>total-ext-length
|
||||
|
||||
\ ClientHello type
|
||||
1 write8
|
||||
|
||||
\ Compute and write length
|
||||
39 addr-session_id_len get8 + addr-suites_num get8 1 << +
|
||||
total-ext-length if 2+ total-ext-length + then
|
||||
write24
|
||||
|
||||
\ Protocol version
|
||||
addr-version_max get16 write16
|
||||
|
||||
\ Client random
|
||||
addr-client_random 4 bzero
|
||||
addr-client_random 4 + 28 mkrand
|
||||
addr-client_random 32 write-blob
|
||||
|
||||
\ Session ID
|
||||
addr-session_id addr-session_id_len get8 write-blob-head8
|
||||
|
||||
\ Supported cipher suites. We also check here that we indeed
|
||||
\ support all these suites.
|
||||
addr-suites_num get8 dup 1 << write16
|
||||
addr-suites_buf swap
|
||||
begin
|
||||
dup while 1-
|
||||
over get16
|
||||
dup suite-supported? ifnot ERR_BAD_CIPHER_SUITE fail then
|
||||
write16
|
||||
swap 2+ swap
|
||||
repeat
|
||||
2drop
|
||||
|
||||
\ Compression methods (only "null" compression)
|
||||
1 write8 0 write8
|
||||
|
||||
\ Extensions
|
||||
total-ext-length if
|
||||
total-ext-length write16
|
||||
ext-reneg-length if
|
||||
0xFF01 write16 \ extension type (0xFF01)
|
||||
addr-saved_finished
|
||||
ext-reneg-length 4 - dup write16 \ extension length
|
||||
1- write-blob-head8 \ verify data
|
||||
then
|
||||
ext-sni-length if
|
||||
0x0000 write16 \ extension type (0)
|
||||
addr-server_name
|
||||
ext-sni-length 4 - dup write16 \ extension length
|
||||
2 - dup write16 \ ServerNameList length
|
||||
0 write8 \ name type: host_name
|
||||
3 - write-blob-head16 \ the name itself
|
||||
then
|
||||
ext-frag-length if
|
||||
0x0001 write16 \ extension type (1)
|
||||
0x0001 write16 \ extension length
|
||||
addr-log_max_frag_len get8 8 - write8
|
||||
then
|
||||
ext-signatures-length if
|
||||
0x000D write16 \ extension type (13)
|
||||
ext-signatures-length 4 - dup write16 \ extension length
|
||||
2 - write16 \ list length
|
||||
supports-ecdsa? if 3 write-hashes then
|
||||
supports-rsa-sign? if 1 write-hashes then
|
||||
then
|
||||
\ TODO: add an API to specify preference order for curves.
|
||||
\ Right now we use increasing id order, which makes P-256
|
||||
\ the preferred curve.
|
||||
ext-supported-curves-length dup if
|
||||
0x000A write16 \ extension type (10)
|
||||
4 - dup write16 \ extension length
|
||||
2- write16 \ list length
|
||||
supported-curves 0
|
||||
begin dup 32 < while
|
||||
dup2 >> 1 and if dup write16 then
|
||||
1+
|
||||
repeat
|
||||
2drop
|
||||
else
|
||||
drop
|
||||
then
|
||||
ext-point-format-length if
|
||||
0x000B write16 \ extension type (11)
|
||||
0x0002 write16 \ extension length
|
||||
0x0100 write16 \ value: 1 format: uncompressed
|
||||
then
|
||||
then
|
||||
;
|
||||
|
||||
\ =======================================================================
|
||||
|
||||
\ Parse server SNI extension. If present, then it should be empty.
|
||||
: read-server-sni ( lim -- lim )
|
||||
read16 if ERR_BAD_SNI fail then ;
|
||||
|
||||
\ Parse server Max Fragment Length extension. If present, then it should
|
||||
\ advertise the same length as the client. Note that whether the server
|
||||
\ sends it or not changes nothing for us: we won't send any record larger
|
||||
\ than the advertised value anyway, and we will accept incoming records
|
||||
\ up to our input buffer length.
|
||||
: read-server-frag ( lim -- lim )
|
||||
read16 1 = ifnot ERR_BAD_FRAGLEN fail then
|
||||
read8 8 + addr-log_max_frag_len get8 = ifnot ERR_BAD_FRAGLEN fail then ;
|
||||
|
||||
\ Parse server Secure Renegotiation extension. This is called only if
|
||||
\ the client sent that extension, so we only have two cases to
|
||||
\ distinguish: first handshake, and renegotiation; in the latter case,
|
||||
\ we know that the server supports the extension, otherwise the client
|
||||
\ would not have sent it.
|
||||
: read-server-reneg ( lim -- lim )
|
||||
read16
|
||||
addr-reneg get8 ifnot
|
||||
\ "reneg" is 0, so this is a first handshake. The server's
|
||||
\ extension MUST be empty. We also learn that the server
|
||||
\ supports the extension.
|
||||
1 = ifnot ERR_BAD_SECRENEG fail then
|
||||
read8 0 = ifnot ERR_BAD_SECRENEG fail then
|
||||
2 addr-reneg set8
|
||||
else
|
||||
\ "reneg" is non-zero, and we sent an extension, so it must
|
||||
\ be 2 and this is a renegotiation. We must verify that
|
||||
\ the extension contents have length exactly 24 bytes and
|
||||
\ match the saved client and server "Finished".
|
||||
25 = ifnot ERR_BAD_SECRENEG fail then
|
||||
read8 24 = ifnot ERR_BAD_SECRENEG fail then
|
||||
addr-pad 24 read-blob
|
||||
addr-saved_finished addr-pad 24 memcmp ifnot
|
||||
ERR_BAD_SECRENEG fail
|
||||
then
|
||||
then ;
|
||||
|
||||
\ Save a value in a 16-bit field, or check it in case of session resumption.
|
||||
: check-resume ( val addr resume -- )
|
||||
if get16 = ifnot ERR_RESUME_MISMATCH fail then else set16 then ;
|
||||
|
||||
cc: DEBUG-BLOB ( addr len -- ) {
|
||||
extern int printf(const char *fmt, ...);
|
||||
|
||||
size_t len = T0_POP();
|
||||
unsigned char *buf = (unsigned char *)CTX + T0_POP();
|
||||
size_t u;
|
||||
|
||||
printf("BLOB:");
|
||||
for (u = 0; u < len; u ++) {
|
||||
if (u % 16 == 0) {
|
||||
printf("\n ");
|
||||
}
|
||||
printf(" %02x", buf[u]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
\ Parse incoming ServerHello. Returned value is true (-1) on session
|
||||
\ resumption.
|
||||
: read-ServerHello ( -- bool )
|
||||
\ Get header, and check message type.
|
||||
read-handshake-header 2 = ifnot ERR_UNEXPECTED fail then
|
||||
|
||||
\ Get protocol version.
|
||||
read16 { version }
|
||||
version addr-version_min get16 < version addr-version_max get16 > or if
|
||||
ERR_UNSUPPORTED_VERSION fail
|
||||
then
|
||||
|
||||
\ Enforce chosen version for subsequent records in both directions.
|
||||
version addr-version_in get16 <> if ERR_BAD_VERSION fail then
|
||||
version addr-version_out set16
|
||||
|
||||
\ Server random.
|
||||
addr-server_random 32 read-blob
|
||||
|
||||
\ The "session resumption" flag.
|
||||
0 { resume }
|
||||
|
||||
\ Session ID.
|
||||
read8 { idlen }
|
||||
idlen 32 > if ERR_OVERSIZED_ID fail then
|
||||
addr-pad idlen read-blob
|
||||
idlen addr-session_id_len get8 = idlen 0 > and if
|
||||
addr-session_id addr-pad idlen memcmp if
|
||||
\ Server session ID is non-empty and matches what
|
||||
\ we sent, so this is a session resumption.
|
||||
-1 >resume
|
||||
then
|
||||
then
|
||||
addr-session_id addr-pad idlen memcpy
|
||||
idlen addr-session_id_len set8
|
||||
|
||||
\ Record version.
|
||||
version addr-version resume check-resume
|
||||
|
||||
\ Cipher suite. We check that it is part of the list of cipher
|
||||
\ suites that we advertised.
|
||||
\ read16 { suite ; found }
|
||||
\ 0 >found
|
||||
\ addr-suites_buf dup addr-suites_num get8 1 << +
|
||||
\ begin dup2 < while
|
||||
\ 2 - dup get16
|
||||
\ suite = found or >found
|
||||
\ repeat
|
||||
\ 2drop found ifnot ERR_BAD_CIPHER_SUITE fail then
|
||||
read16
|
||||
dup scan-suite 0< if ERR_BAD_CIPHER_SUITE fail then
|
||||
addr-cipher_suite resume check-resume
|
||||
|
||||
\ Compression method. Should be 0 (no compression).
|
||||
read8 if ERR_BAD_COMPRESSION fail then
|
||||
|
||||
\ Parse extensions (if any). If there is no extension, then the
|
||||
\ read limit (on the TOS) should be 0 at that point.
|
||||
dup if
|
||||
\ Length of extension list.
|
||||
\ message size.
|
||||
read16 open-elt
|
||||
|
||||
\ Enumerate extensions. For each of them, check that we
|
||||
\ sent an extension of that type, and did not see it
|
||||
\ yet; and then process it.
|
||||
ext-sni-length { ok-sni }
|
||||
ext-reneg-length { ok-reneg }
|
||||
ext-frag-length { ok-frag }
|
||||
ext-signatures-length { ok-signatures }
|
||||
ext-supported-curves-length { ok-curves }
|
||||
ext-point-format-length { ok-points }
|
||||
begin dup while
|
||||
read16
|
||||
case
|
||||
\ Server Name Indication. The server may
|
||||
\ send such an extension if it uses the SNI
|
||||
\ from the client, but that "response
|
||||
\ extension" is supposed to be empty.
|
||||
0x0000 of
|
||||
ok-sni ifnot
|
||||
ERR_EXTRA_EXTENSION fail
|
||||
then
|
||||
0 >ok-sni
|
||||
read-server-sni
|
||||
endof
|
||||
|
||||
\ Max Frag Length. The contents shall be
|
||||
\ a single byte whose value matches the one
|
||||
\ sent by the client.
|
||||
0x0001 of
|
||||
ok-frag ifnot
|
||||
ERR_EXTRA_EXTENSION fail
|
||||
then
|
||||
0 >ok-frag
|
||||
read-server-frag
|
||||
endof
|
||||
|
||||
\ Secure Renegotiation.
|
||||
0xFF01 of
|
||||
ok-reneg ifnot
|
||||
ERR_EXTRA_EXTENSION fail
|
||||
then
|
||||
0 >ok-reneg
|
||||
read-server-reneg
|
||||
endof
|
||||
|
||||
\ Signature Algorithms.
|
||||
\ Normally, the server should never send this
|
||||
\ extension (so says RFC 5246 #7.4.1.4.1),
|
||||
\ but some existing servers do.
|
||||
0x000D of
|
||||
ok-signatures ifnot
|
||||
ERR_EXTRA_EXTENSION fail
|
||||
then
|
||||
0 >ok-signatures
|
||||
read-ignore-16
|
||||
endof
|
||||
|
||||
\ Supported Curves.
|
||||
0x000A of
|
||||
ok-curves ifnot
|
||||
ERR_EXTRA_EXTENSION fail
|
||||
then
|
||||
0 >ok-curves
|
||||
read-ignore-16
|
||||
endof
|
||||
|
||||
\ Supported Point Formats.
|
||||
0x000B of
|
||||
ok-points ifnot
|
||||
ERR_EXTRA_EXTENSION fail
|
||||
then
|
||||
0 >ok-points
|
||||
read-ignore-16
|
||||
endof
|
||||
|
||||
ERR_EXTRA_EXTENSION fail
|
||||
endcase
|
||||
repeat
|
||||
|
||||
\ If we sent a secure renegotiation extension but did not
|
||||
\ receive a response, then the server does not support
|
||||
\ secure renegotiation. This is a hard failure if this
|
||||
\ is a renegotiation.
|
||||
ok-reneg if
|
||||
ok-reneg 5 > if ERR_BAD_SECRENEG fail then
|
||||
1 addr-reneg set8
|
||||
then
|
||||
close-elt
|
||||
then
|
||||
close-elt
|
||||
resume
|
||||
;
|
||||
|
||||
cc: x509-start-chain ( expected-key-type -- ) {
|
||||
const br_x509_class *xc;
|
||||
|
||||
xc = *(ENG->x509ctx);
|
||||
xc->start_chain(ENG->x509ctx, T0_POP(), ENG->server_name);
|
||||
}
|
||||
|
||||
cc: x509-start-cert ( length -- ) {
|
||||
const br_x509_class *xc;
|
||||
|
||||
xc = *(ENG->x509ctx);
|
||||
xc->start_cert(ENG->x509ctx, T0_POP());
|
||||
}
|
||||
|
||||
cc: x509-append ( length -- ) {
|
||||
const br_x509_class *xc;
|
||||
size_t len;
|
||||
|
||||
xc = *(ENG->x509ctx);
|
||||
len = T0_POP();
|
||||
xc->append(ENG->x509ctx, ENG->pad, len);
|
||||
}
|
||||
|
||||
cc: x509-end-cert ( -- ) {
|
||||
const br_x509_class *xc;
|
||||
|
||||
xc = *(ENG->x509ctx);
|
||||
xc->end_cert(ENG->x509ctx);
|
||||
}
|
||||
|
||||
cc: x509-end-chain ( -- err ) {
|
||||
const br_x509_class *xc;
|
||||
|
||||
xc = *(ENG->x509ctx);
|
||||
T0_PUSH(xc->end_chain(ENG->x509ctx));
|
||||
}
|
||||
|
||||
\ Parse Certificate
|
||||
: read-Certificate ( -- )
|
||||
\ Get header, and check message type.
|
||||
read-handshake-header 11 = ifnot ERR_UNEXPECTED fail then
|
||||
|
||||
\ Start processing the chain through the X.509 engine.
|
||||
addr-cipher_suite get16 expected-key-type
|
||||
x509-start-chain
|
||||
|
||||
\ Total chain length is a 24-bit integer.
|
||||
read24 open-elt
|
||||
begin
|
||||
dup while
|
||||
read24 open-elt
|
||||
dup x509-start-cert
|
||||
|
||||
\ We read the certificate by chunks through the pad, so
|
||||
\ as to use the existing reading function (read-blob)
|
||||
\ that also ensures proper hashing.
|
||||
begin
|
||||
dup while
|
||||
dup 256 > if 256 else dup then { len }
|
||||
addr-pad len read-blob
|
||||
len x509-append
|
||||
repeat
|
||||
close-elt
|
||||
x509-end-cert
|
||||
repeat
|
||||
|
||||
\ We must close the chain AND the handshake message.
|
||||
close-elt
|
||||
close-elt
|
||||
|
||||
\ Chain processing is finished; get the error code.
|
||||
x509-end-chain
|
||||
dup if fail then drop
|
||||
;
|
||||
|
||||
\ Verify signature on ECDHE point sent by the server.
|
||||
\ 'hash' is the hash function to use (1 to 6, or 0 for RSA with MD5+SHA-1)
|
||||
\ 'use-rsa' is 0 for ECDSA, -1 for for RSA
|
||||
\ 'sig-len' is the signature length (in bytes)
|
||||
\ The signature itself is in the pad.
|
||||
cc: verify-SKE-sig ( hash use-rsa sig-len -- err ) {
|
||||
size_t sig_len = T0_POP();
|
||||
int use_rsa = T0_POPi();
|
||||
int hash = T0_POPi();
|
||||
|
||||
T0_PUSH(verify_SKE_sig(CTX, hash, use_rsa, sig_len));
|
||||
}
|
||||
|
||||
\ Parse ServerKeyExchange
|
||||
: read-ServerKeyExchange ( -- )
|
||||
\ Get header, and check message type.
|
||||
read-handshake-header 12 = ifnot ERR_UNEXPECTED fail then
|
||||
|
||||
\ We expect a named curve, and we must support it.
|
||||
read8 3 = ifnot ERR_INVALID_ALGORITHM fail then
|
||||
read16 dup addr-ecdhe_curve set8
|
||||
dup 32 >= if ERR_INVALID_ALGORITHM fail then
|
||||
supported-curves swap >> 1 and ifnot ERR_INVALID_ALGORITHM fail then
|
||||
|
||||
\ Read the server point.
|
||||
read8
|
||||
dup 133 > if ERR_INVALID_ALGORITHM fail then
|
||||
dup addr-ecdhe_point_len set8
|
||||
addr-ecdhe_point swap read-blob
|
||||
|
||||
\ If using TLS-1.2+, then the hash function and signature algorithm
|
||||
\ are explicitly provided; the signature algorithm must match what
|
||||
\ the cipher suite specifies. With TLS-1.0 and 1.1, the signature
|
||||
\ algorithm is inferred from the cipher suite, and the hash is
|
||||
\ either MD5+SHA-1 (for RSA signatures) or SHA-1 (for ECDSA).
|
||||
addr-version get16 0x0303 >= { tls1.2+ }
|
||||
addr-cipher_suite get16 use-rsa-ecdhe? { use-rsa }
|
||||
2 { hash }
|
||||
tls1.2+ if
|
||||
\ Read hash function; accept only the SHA-* identifiers
|
||||
\ (from SHA-1 to SHA-512, no MD5 here).
|
||||
read8
|
||||
dup dup 2 < swap 6 > or if ERR_INVALID_ALGORITHM fail then
|
||||
>hash
|
||||
read8
|
||||
\ Get expected signature algorithm and compare with what
|
||||
\ the server just sent. Expected value is 1 for RSA, 3
|
||||
\ for ECDSA. Note that 'use-rsa' evaluates to -1 for RSA,
|
||||
\ 0 for ECDSA.
|
||||
use-rsa 1 << 3 + = ifnot ERR_INVALID_ALGORITHM fail then
|
||||
else
|
||||
\ For MD5+SHA-1, we set 'hash' to 0.
|
||||
use-rsa if 0 >hash then
|
||||
then
|
||||
|
||||
\ Read signature into the pad.
|
||||
read16 dup { sig-len }
|
||||
|
||||
dup 512 > if ERR_LIMIT_EXCEEDED fail then
|
||||
addr-pad swap read-blob
|
||||
|
||||
\ Verify signature.
|
||||
hash use-rsa sig-len verify-SKE-sig
|
||||
dup if fail then drop
|
||||
|
||||
close-elt ;
|
||||
|
||||
\ Parse CertificateRequest. Header has already been read.
|
||||
: read-contents-CertificateRequest ( lim -- )
|
||||
\ TODO: implement client certificates. Right now, we simply
|
||||
\ drop the complete message.
|
||||
begin dup while read8 drop repeat drop ;
|
||||
|
||||
\ Write an empty Certificate message.
|
||||
: write-empty-Certificate ( -- )
|
||||
11 write8 3 write24 0 write24 ;
|
||||
|
||||
cc: do-rsa-encrypt ( prf_id -- nlen ) {
|
||||
int x;
|
||||
|
||||
x = make_pms_rsa(CTX, T0_POP());
|
||||
if (x < 0) {
|
||||
br_ssl_engine_fail(ENG, -x);
|
||||
T0_CO();
|
||||
} else {
|
||||
T0_PUSH(x);
|
||||
}
|
||||
}
|
||||
|
||||
cc: do-ecdh ( echde prf_id -- ulen ) {
|
||||
unsigned prf_id = T0_POP();
|
||||
unsigned ecdhe = T0_POP();
|
||||
int x;
|
||||
|
||||
x = make_pms_ecdh(CTX, ecdhe, prf_id);
|
||||
if (x < 0) {
|
||||
br_ssl_engine_fail(ENG, -x);
|
||||
T0_CO();
|
||||
} else {
|
||||
T0_PUSH(x);
|
||||
}
|
||||
}
|
||||
|
||||
\ Write ClientKeyExchange
|
||||
: write-ClientKeyExchange ( -- )
|
||||
16 write8
|
||||
addr-cipher_suite get16
|
||||
dup use-rsa-keyx? if
|
||||
prf-id do-rsa-encrypt
|
||||
dup 2+ write24
|
||||
dup write16
|
||||
addr-pad swap write-blob
|
||||
else
|
||||
dup use-ecdhe? swap prf-id do-ecdh
|
||||
dup 1+ write24
|
||||
dup write8
|
||||
addr-pad swap write-blob
|
||||
then ;
|
||||
|
||||
\ =======================================================================
|
||||
|
||||
\ Perform a handshake.
|
||||
: do-handshake ( -- )
|
||||
0 addr-application_data set8
|
||||
22 addr-record_type_out set8
|
||||
multihash-init
|
||||
|
||||
write-ClientHello
|
||||
flush-record
|
||||
read-ServerHello
|
||||
|
||||
if
|
||||
\ Session resumption.
|
||||
-1 read-CCS-Finished
|
||||
-1 write-CCS-Finished
|
||||
|
||||
else
|
||||
|
||||
\ Not a session resumption.
|
||||
|
||||
read-Certificate
|
||||
|
||||
\ Depending on cipher suite, we may now expect a
|
||||
\ ServerKeyExchange.
|
||||
addr-cipher_suite get16 expected-key-type
|
||||
CX 0 63 { BR_KEYTYPE_SIGN } and if
|
||||
read-ServerKeyExchange
|
||||
then
|
||||
|
||||
\ Get next header.
|
||||
read-handshake-header
|
||||
|
||||
\ If this is a CertificateRequest, parse it, then read
|
||||
\ next header.
|
||||
dup 13 = if
|
||||
drop read-contents-CertificateRequest
|
||||
read-handshake-header
|
||||
-1
|
||||
else
|
||||
0
|
||||
then
|
||||
{ seen-CR }
|
||||
|
||||
\ At that point, we should have a ServerHelloDone,
|
||||
\ whose length must be 0.
|
||||
14 = ifnot ERR_UNEXPECTED fail then
|
||||
if ERR_BAD_HELLO_DONE fail then
|
||||
|
||||
\ There should not be more bytes in the record at that point.
|
||||
more-incoming-bytes? if ERR_UNEXPECTED fail then
|
||||
|
||||
seen-CR if
|
||||
\ TODO: client certificate support.
|
||||
write-empty-Certificate
|
||||
then
|
||||
write-ClientKeyExchange
|
||||
|
||||
\ TODO: CertificateVerify
|
||||
|
||||
-1 write-CCS-Finished
|
||||
-1 read-CCS-Finished
|
||||
then
|
||||
|
||||
\ Now we should be invoked only in case of renegotiation.
|
||||
1 addr-application_data set8
|
||||
23 addr-record_type_out set8 ;
|
||||
|
||||
\ Read a HelloRequest message.
|
||||
: read-HelloRequest ( -- )
|
||||
\ A HelloRequest has length 0 and type 0.
|
||||
read-handshake-header-core
|
||||
if ERR_UNEXPECTED fail then
|
||||
if ERR_BAD_HANDSHAKE fail then ;
|
||||
|
||||
\ Entry point.
|
||||
: main ( -- ! )
|
||||
\ Perform initial handshake.
|
||||
do-handshake
|
||||
|
||||
begin
|
||||
\ Wait for further invocation. At that point, we should
|
||||
\ get either an explicit call for renegotiation, or
|
||||
\ an incoming HelloRequest handshake message.
|
||||
wait-co
|
||||
dup 0x07 and case
|
||||
0x00 of
|
||||
0x10 and if
|
||||
do-handshake
|
||||
then
|
||||
endof
|
||||
0x01 of
|
||||
drop
|
||||
0 addr-application_data set8
|
||||
read-HelloRequest
|
||||
\ Reject renegotiations if the peer does not
|
||||
\ support secure renegotiation. Theoretically
|
||||
\ we could just ignore that, however if the
|
||||
\ server sent an HelloRequest then it is
|
||||
\ expecting a handshake and will wait for our
|
||||
\ ClientHello.
|
||||
addr-reneg get8 1 = if
|
||||
flush-record
|
||||
begin can-output? not while
|
||||
wait-co drop
|
||||
repeat
|
||||
100 send-warning
|
||||
else
|
||||
do-handshake
|
||||
then
|
||||
endof
|
||||
ERR_UNEXPECTED fail
|
||||
endcase
|
||||
again
|
||||
;
|
||||
1012
src/ssl/ssl_hs_common.t0
Normal file
1012
src/ssl/ssl_hs_common.t0
Normal file
File diff suppressed because it is too large
Load diff
1479
src/ssl/ssl_hs_server.c
Normal file
1479
src/ssl/ssl_hs_server.c
Normal file
File diff suppressed because it is too large
Load diff
1013
src/ssl/ssl_hs_server.t0
Normal file
1013
src/ssl/ssl_hs_server.t0
Normal file
File diff suppressed because it is too large
Load diff
255
src/ssl/ssl_io.c
Normal file
255
src/ssl/ssl_io.c
Normal file
|
|
@ -0,0 +1,255 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "inner.h"
|
||||
|
||||
/* see bearssl_ssl.h */
|
||||
void
|
||||
br_sslio_init(br_sslio_context *ctx,
|
||||
br_ssl_engine_context *engine,
|
||||
int (*low_read)(void *read_context,
|
||||
unsigned char *data, size_t len),
|
||||
void *read_context,
|
||||
int (*low_write)(void *write_context,
|
||||
const unsigned char *data, size_t len),
|
||||
void *write_context)
|
||||
{
|
||||
ctx->engine = engine;
|
||||
ctx->low_read = low_read;
|
||||
ctx->read_context = read_context;
|
||||
ctx->low_write = low_write;
|
||||
ctx->write_context = write_context;
|
||||
}
|
||||
|
||||
/*
|
||||
* Run the engine, until the specified target state is achieved, or
|
||||
* an error occurs. The target state is SENDAPP, RECVAPP, or the
|
||||
* combination of both (the combination matches either). When a match is
|
||||
* achieved, this function returns 0. On error, it returns -1.
|
||||
*/
|
||||
static int
|
||||
run_until(br_sslio_context *ctx, unsigned target)
|
||||
{
|
||||
for (;;) {
|
||||
unsigned state;
|
||||
|
||||
state = br_ssl_engine_current_state(ctx->engine);
|
||||
if (state & BR_SSL_CLOSED) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* If there is some record data to send, do it. This takes
|
||||
* precedence over everything else.
|
||||
*/
|
||||
if (state & BR_SSL_SENDREC) {
|
||||
unsigned char *buf;
|
||||
size_t len;
|
||||
int wlen;
|
||||
|
||||
buf = br_ssl_engine_sendrec_buf(ctx->engine, &len);
|
||||
wlen = ctx->low_write(ctx->write_context, buf, len);
|
||||
if (wlen < 0) {
|
||||
/*
|
||||
* If we received a close_notify and we
|
||||
* still send something, then we have our
|
||||
* own response close_notify to send, and
|
||||
* the peer is allowed by RFC 5246 not to
|
||||
* wait for it.
|
||||
*/
|
||||
if (!ctx->engine->shutdown_recv) {
|
||||
br_ssl_engine_fail(
|
||||
ctx->engine, BR_ERR_IO);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
if (wlen > 0) {
|
||||
br_ssl_engine_sendrec_ack(ctx->engine, wlen);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we reached our target, then we are finished.
|
||||
*/
|
||||
if (state & target) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* If some application data must be read, and we did not
|
||||
* exit, then this means that we are trying to write data,
|
||||
* and that's not possible until the application data is
|
||||
* read. This may happen if using a shared in/out buffer,
|
||||
* and the underlying protocol is not strictly half-duplex.
|
||||
* This is unrecoverable here, so we report an error.
|
||||
*/
|
||||
if (state & BR_SSL_RECVAPP) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we reached that point, then either we are trying
|
||||
* to read data and there is some, or the engine is stuck
|
||||
* until a new record is obtained.
|
||||
*/
|
||||
if (state & BR_SSL_RECVREC) {
|
||||
unsigned char *buf;
|
||||
size_t len;
|
||||
int rlen;
|
||||
|
||||
buf = br_ssl_engine_recvrec_buf(ctx->engine, &len);
|
||||
rlen = ctx->low_read(ctx->read_context, buf, len);
|
||||
if (rlen < 0) {
|
||||
br_ssl_engine_fail(ctx->engine, BR_ERR_IO);
|
||||
return -1;
|
||||
}
|
||||
if (rlen > 0) {
|
||||
br_ssl_engine_recvrec_ack(ctx->engine, rlen);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* We can reach that point if the target RECVAPP, and
|
||||
* the state contains SENDAPP only. This may happen with
|
||||
* a shared in/out buffer. In that case, we must flush
|
||||
* the buffered data to "make room" for a new incoming
|
||||
* record.
|
||||
*/
|
||||
br_ssl_engine_flush(ctx->engine, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* see bearssl_ssl.h */
|
||||
int
|
||||
br_sslio_read(br_sslio_context *ctx, void *dst, size_t len)
|
||||
{
|
||||
unsigned char *buf;
|
||||
size_t alen;
|
||||
|
||||
if (run_until(ctx, BR_SSL_RECVAPP) < 0) {
|
||||
return -1;
|
||||
}
|
||||
buf = br_ssl_engine_recvapp_buf(ctx->engine, &alen);
|
||||
if (alen > len) {
|
||||
alen = len;
|
||||
}
|
||||
memcpy(dst, buf, alen);
|
||||
br_ssl_engine_recvapp_ack(ctx->engine, alen);
|
||||
return (int)alen;
|
||||
}
|
||||
|
||||
/* see bearssl_ssl.h */
|
||||
int
|
||||
br_sslio_read_all(br_sslio_context *ctx, void *dst, size_t len)
|
||||
{
|
||||
unsigned char *buf;
|
||||
|
||||
buf = dst;
|
||||
while (len > 0) {
|
||||
int rlen;
|
||||
|
||||
rlen = br_sslio_read(ctx, buf, len);
|
||||
if (rlen < 0) {
|
||||
return -1;
|
||||
}
|
||||
buf += rlen;
|
||||
len -= (size_t)rlen;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* see bearssl_ssl.h */
|
||||
int
|
||||
br_sslio_write(br_sslio_context *ctx, const void *src, size_t len)
|
||||
{
|
||||
unsigned char *buf;
|
||||
size_t alen;
|
||||
|
||||
if (run_until(ctx, BR_SSL_SENDAPP) < 0) {
|
||||
return -1;
|
||||
}
|
||||
buf = br_ssl_engine_sendapp_buf(ctx->engine, &alen);
|
||||
if (alen > len) {
|
||||
alen = len;
|
||||
}
|
||||
memcpy(buf, src, alen);
|
||||
br_ssl_engine_sendapp_ack(ctx->engine, alen);
|
||||
return (int)alen;
|
||||
}
|
||||
|
||||
/* see bearssl_ssl.h */
|
||||
int
|
||||
br_sslio_write_all(br_sslio_context *ctx, const void *src, size_t len)
|
||||
{
|
||||
const unsigned char *buf;
|
||||
|
||||
buf = src;
|
||||
while (len > 0) {
|
||||
int wlen;
|
||||
|
||||
wlen = br_sslio_write(ctx, buf, len);
|
||||
if (wlen < 0) {
|
||||
return -1;
|
||||
}
|
||||
buf += wlen;
|
||||
len -= (size_t)wlen;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* see bearssl_ssl.h */
|
||||
int
|
||||
br_sslio_flush(br_sslio_context *ctx)
|
||||
{
|
||||
/*
|
||||
* We trigger a flush. We know the data is gone when there is
|
||||
* no longer any record data to send, and we can either read
|
||||
* or write application data. The call to run_until() does the
|
||||
* job because it ensures that any assembled record data is
|
||||
* first sent down the wire before considering anything else.
|
||||
*/
|
||||
br_ssl_engine_flush(ctx->engine, 0);
|
||||
return run_until(ctx, BR_SSL_SENDAPP | BR_SSL_RECVAPP);
|
||||
}
|
||||
|
||||
/* see bearssl_ssl.h */
|
||||
int
|
||||
br_sslio_close(br_sslio_context *ctx)
|
||||
{
|
||||
br_ssl_engine_close(ctx->engine);
|
||||
while (br_ssl_engine_current_state(ctx->engine) != BR_SSL_CLOSED) {
|
||||
/*
|
||||
* Discard any incoming application data.
|
||||
*/
|
||||
size_t len;
|
||||
|
||||
run_until(ctx, BR_SSL_RECVAPP);
|
||||
if (br_ssl_engine_recvapp_buf(ctx->engine, &len) != NULL) {
|
||||
br_ssl_engine_recvapp_ack(ctx->engine, len);
|
||||
}
|
||||
}
|
||||
return br_ssl_engine_last_error(ctx->engine) == BR_ERR_OK;
|
||||
}
|
||||
424
src/ssl/ssl_lru.c
Normal file
424
src/ssl/ssl_lru.c
Normal file
|
|
@ -0,0 +1,424 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "inner.h"
|
||||
|
||||
/*
|
||||
* Each entry consists in a fixed number of bytes. Entries are concatenated
|
||||
* in the store block. "Addresses" are really offsets in the block,
|
||||
* expressed over 32 bits (so the cache may have size at most 4 GB, which
|
||||
* "ought to be enough for everyone"). The "null address" is 0xFFFFFFFF.
|
||||
* Note that since the storage block alignment is in no way guaranted, we
|
||||
* perform only accesses that can handle unaligned data.
|
||||
*
|
||||
* Two concurrent data structures are maintained:
|
||||
*
|
||||
* -- Entries are organised in a doubly-linked list; saved entries are added
|
||||
* at the head, and loaded entries are moved to the head. Eviction uses
|
||||
* the list tail (this is the LRU algorithm).
|
||||
*
|
||||
* -- Entries are indexed with a binary tree: all left descendants of a
|
||||
* node have a lower session ID (in lexicographic order), while all
|
||||
* right descendants have a higher session ID. The tree is balanced.
|
||||
*
|
||||
* Entry format:
|
||||
*
|
||||
* session ID 32 bytes
|
||||
* master secret 48 bytes
|
||||
* protocol version 2 bytes (big endian)
|
||||
* cipher suite 2 bytes (big endian)
|
||||
* list prev 4 bytes (big endian)
|
||||
* list next 4 bytes (big endian)
|
||||
* tree left child 4 bytes (big endian)
|
||||
* tree right child 4 bytes (big endian)
|
||||
* tree node colour 1 byte (0 = red, 1 = black)
|
||||
*
|
||||
* We need to keep the tree balanced because an attacker could make
|
||||
* handshakes, selecting some specific sessions (by reusing them) to
|
||||
* try to make us make an imbalanced tree that makes lookups expensive
|
||||
* (a denial-of-service attack that would persist as long as the cache
|
||||
* remains, i.e. even after the attacker made all his connections).
|
||||
* To do that, we replace the session ID (or the start of the session ID)
|
||||
* with a HMAC value computed over the replaced part; the hash function
|
||||
* implementation and the key are obtained from the server context upon
|
||||
* first save() call.
|
||||
*/
|
||||
#define SESSION_ID_LEN 32
|
||||
#define MASTER_SECRET_LEN 48
|
||||
|
||||
#define SESSION_ID_OFF 0
|
||||
#define MASTER_SECRET_OFF 32
|
||||
#define VERSION_OFF 80
|
||||
#define CIPHER_SUITE_OFF 82
|
||||
#define LIST_PREV_OFF 84
|
||||
#define LIST_NEXT_OFF 88
|
||||
#define TREE_LEFT_OFF 92
|
||||
#define TREE_RIGHT_OFF 96
|
||||
|
||||
#define LRU_ENTRY_LEN 100
|
||||
|
||||
#define ADDR_NULL ((uint32_t)-1)
|
||||
|
||||
#define GETSET(name, off) \
|
||||
static inline uint32_t get_ ## name(br_ssl_session_cache_lru *cc, uint32_t x) \
|
||||
{ \
|
||||
return br_dec32be(cc->store + x + (off)); \
|
||||
} \
|
||||
static inline void set_ ## name(br_ssl_session_cache_lru *cc, \
|
||||
uint32_t x, uint32_t val) \
|
||||
{ \
|
||||
br_enc32be(cc->store + x + (off), val); \
|
||||
}
|
||||
|
||||
GETSET(prev, LIST_PREV_OFF)
|
||||
GETSET(next, LIST_NEXT_OFF)
|
||||
GETSET(left, TREE_LEFT_OFF)
|
||||
GETSET(right, TREE_RIGHT_OFF)
|
||||
|
||||
/*
|
||||
* Transform the session ID by replacing the first N bytes with a HMAC
|
||||
* value computed over these bytes, using the random key K (the HMAC
|
||||
* value is truncated if needed). HMAC will use the same hash function
|
||||
* as the DRBG in the SSL server context, so with SHA-256, SHA-384,
|
||||
* or SHA-1, depending on what is available.
|
||||
*
|
||||
* The risk of collision is considered too small to be a concern; and
|
||||
* the impact of a collision is low (the handshake won't succeed). This
|
||||
* risk is much lower than any transmission error, which would lead to
|
||||
* the same consequences.
|
||||
*/
|
||||
static void
|
||||
mask_id(br_ssl_session_cache_lru *cc,
|
||||
const unsigned char *src, unsigned char *dst)
|
||||
{
|
||||
br_hmac_key_context hkc;
|
||||
br_hmac_context hc;
|
||||
|
||||
memcpy(dst, src, SESSION_ID_LEN);
|
||||
br_hmac_key_init(&hkc, cc->hash, cc->index_key, sizeof cc->index_key);
|
||||
br_hmac_init(&hc, &hkc, SESSION_ID_LEN);
|
||||
br_hmac_update(&hc, src, SESSION_ID_LEN);
|
||||
br_hmac_out(&hc, dst);
|
||||
}
|
||||
|
||||
/*
|
||||
* Find a node by ID. Returned value is the node address, or ADDR_NULL if
|
||||
* the node is not found.
|
||||
*
|
||||
* If addr_link is not NULL, then '*addr_link' is set to the address of the
|
||||
* last followed link. If the found node is the root, then '*addr_link' is
|
||||
* set to ADDR_NULL.
|
||||
*/
|
||||
static uint32_t
|
||||
find_node(br_ssl_session_cache_lru *cc, const unsigned char *id,
|
||||
uint32_t *addr_link)
|
||||
{
|
||||
uint32_t x, y;
|
||||
|
||||
x = cc->root;
|
||||
y = ADDR_NULL;
|
||||
while (x != ADDR_NULL) {
|
||||
int r;
|
||||
|
||||
r = memcmp(id, cc->store + x + SESSION_ID_OFF, SESSION_ID_LEN);
|
||||
if (r < 0) {
|
||||
y = x + TREE_LEFT_OFF;
|
||||
x = get_left(cc, x);
|
||||
} else if (r == 0) {
|
||||
if (addr_link != NULL) {
|
||||
*addr_link = y;
|
||||
}
|
||||
return x;
|
||||
} else {
|
||||
y = x + TREE_RIGHT_OFF;
|
||||
x = get_right(cc, x);
|
||||
}
|
||||
}
|
||||
if (addr_link != NULL) {
|
||||
*addr_link = y;
|
||||
}
|
||||
return ADDR_NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* For node x, find its replacement upon removal.
|
||||
*
|
||||
* -- If node x has no child, then this returns ADDR_NULL.
|
||||
* -- Otherwise, if node x has a left child, then the replacement is the
|
||||
* rightmost left-descendent.
|
||||
* -- Otherwise, the replacement is the leftmost right-descendent.
|
||||
*
|
||||
* If a node is returned, then '*al' is set to the address of the field
|
||||
* that points to that node.
|
||||
*/
|
||||
static uint32_t
|
||||
find_replacement_node(br_ssl_session_cache_lru *cc, uint32_t x, uint32_t *al)
|
||||
{
|
||||
uint32_t y1, y2;
|
||||
|
||||
y1 = get_left(cc, x);
|
||||
if (y1 != ADDR_NULL) {
|
||||
y2 = x + TREE_LEFT_OFF;
|
||||
for (;;) {
|
||||
uint32_t z;
|
||||
|
||||
z = get_right(cc, y1);
|
||||
if (z == ADDR_NULL) {
|
||||
*al = y2;
|
||||
return y1;
|
||||
}
|
||||
y2 = y1 + TREE_RIGHT_OFF;
|
||||
y1 = z;
|
||||
}
|
||||
}
|
||||
y1 = get_right(cc, x);
|
||||
if (y1 != ADDR_NULL) {
|
||||
y2 = x + TREE_RIGHT_OFF;
|
||||
for (;;) {
|
||||
uint32_t z;
|
||||
|
||||
z = get_left(cc, y1);
|
||||
if (z == ADDR_NULL) {
|
||||
*al = y2;
|
||||
return y1;
|
||||
}
|
||||
y2 = y1 + TREE_LEFT_OFF;
|
||||
y1 = z;
|
||||
}
|
||||
}
|
||||
*al = ADDR_NULL;
|
||||
return ADDR_NULL;
|
||||
}
|
||||
|
||||
static inline void
|
||||
set_link(br_ssl_session_cache_lru *cc, uint32_t alx, uint32_t x)
|
||||
{
|
||||
if (alx == ADDR_NULL) {
|
||||
cc->root = x;
|
||||
} else {
|
||||
br_enc32be(cc->store + alx, x);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
remove_node(br_ssl_session_cache_lru *cc, uint32_t x)
|
||||
{
|
||||
uint32_t alx, y, aly;
|
||||
|
||||
/*
|
||||
* Find node back and its ancestor link.
|
||||
*/
|
||||
find_node(cc, cc->store + x + SESSION_ID_OFF, &alx);
|
||||
|
||||
/*
|
||||
* Find replacement node.
|
||||
*/
|
||||
y = find_replacement_node(cc, x, &aly);
|
||||
|
||||
/*
|
||||
* Unlink replacement node.
|
||||
*/
|
||||
set_link(cc, aly, ADDR_NULL);
|
||||
|
||||
/*
|
||||
* Link the replacement node in its new place.
|
||||
*/
|
||||
set_link(cc, alx, y);
|
||||
}
|
||||
|
||||
static void
|
||||
lru_save(const br_ssl_session_cache_class **ctx,
|
||||
br_ssl_server_context *server_ctx,
|
||||
const br_ssl_session_parameters *params)
|
||||
{
|
||||
br_ssl_session_cache_lru *cc;
|
||||
unsigned char id[SESSION_ID_LEN];
|
||||
uint32_t x, alx;
|
||||
|
||||
cc = (br_ssl_session_cache_lru *)ctx;
|
||||
|
||||
/*
|
||||
* If the buffer is too small, we don't record anything. This
|
||||
* test avoids problems in subsequent code.
|
||||
*/
|
||||
if (cc->store_len < LRU_ENTRY_LEN) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Upon the first save in a session cache instance, we obtain
|
||||
* a random key for our indexing.
|
||||
*/
|
||||
if (!cc->init_done) {
|
||||
br_hmac_drbg_generate(&server_ctx->eng.rng,
|
||||
cc->index_key, sizeof cc->index_key);
|
||||
cc->hash = br_hmac_drbg_get_hash(&server_ctx->eng.rng);
|
||||
cc->init_done = 1;
|
||||
}
|
||||
mask_id(cc, params->session_id, id);
|
||||
|
||||
/*
|
||||
* Look for the node in the tree. If the same ID is already used,
|
||||
* then reject it. This is a collision event, which should be
|
||||
* exceedingly rare.
|
||||
* Note: we do NOT record the emplacement here, because the
|
||||
* removal of an entry may change the tree topology.
|
||||
*/
|
||||
if (find_node(cc, id, NULL) != ADDR_NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find some room for the new parameters. If the cache is not
|
||||
* full yet, add it to the end of the area and bump the pointer up.
|
||||
* Otherwise, evict the list tail entry. Note that we already
|
||||
* filtered out the case of a ridiculously small buffer that
|
||||
* cannot hold any entry at all; thus, if there is no room for an
|
||||
* extra entry, then the cache cannot be empty.
|
||||
*/
|
||||
if (cc->store_ptr > (cc->store_len - LRU_ENTRY_LEN)) {
|
||||
/*
|
||||
* Evict tail. If the buffer has room for a single entry,
|
||||
* then this may also be the head.
|
||||
*/
|
||||
x = cc->tail;
|
||||
cc->tail = get_prev(cc, x);
|
||||
if (cc->tail == ADDR_NULL) {
|
||||
cc->head = ADDR_NULL;
|
||||
} else {
|
||||
set_next(cc, cc->tail, ADDR_NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove the node from the tree.
|
||||
*/
|
||||
remove_node(cc, x);
|
||||
} else {
|
||||
/*
|
||||
* Allocate room for new node.
|
||||
*/
|
||||
x = cc->store_ptr;
|
||||
cc->store_ptr += LRU_ENTRY_LEN;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find the emplacement for the new node, and link it.
|
||||
*/
|
||||
find_node(cc, id, &alx);
|
||||
set_link(cc, alx, x);
|
||||
set_left(cc, x, ADDR_NULL);
|
||||
set_right(cc, x, ADDR_NULL);
|
||||
|
||||
/*
|
||||
* New entry becomes new list head. It may also become the list
|
||||
* tail if the cache was empty at that point.
|
||||
*/
|
||||
if (cc->head == ADDR_NULL) {
|
||||
cc->tail = x;
|
||||
} else {
|
||||
set_prev(cc, cc->head, x);
|
||||
}
|
||||
set_prev(cc, x, ADDR_NULL);
|
||||
set_next(cc, x, cc->head);
|
||||
cc->head = x;
|
||||
|
||||
/*
|
||||
* Fill data in the entry.
|
||||
*/
|
||||
memcpy(cc->store + x + SESSION_ID_OFF, id, SESSION_ID_LEN);
|
||||
memcpy(cc->store + x + MASTER_SECRET_OFF,
|
||||
params->master_secret, MASTER_SECRET_LEN);
|
||||
br_enc16be(cc->store + x + VERSION_OFF, params->version);
|
||||
br_enc16be(cc->store + x + CIPHER_SUITE_OFF, params->cipher_suite);
|
||||
}
|
||||
|
||||
static int
|
||||
lru_load(const br_ssl_session_cache_class **ctx,
|
||||
br_ssl_server_context *server_ctx,
|
||||
br_ssl_session_parameters *params)
|
||||
{
|
||||
br_ssl_session_cache_lru *cc;
|
||||
unsigned char id[SESSION_ID_LEN];
|
||||
uint32_t x;
|
||||
|
||||
(void)server_ctx;
|
||||
cc = (br_ssl_session_cache_lru *)ctx;
|
||||
if (!cc->init_done) {
|
||||
return 0;
|
||||
}
|
||||
mask_id(cc, params->session_id, id);
|
||||
x = find_node(cc, id, NULL);
|
||||
if (x != ADDR_NULL) {
|
||||
params->version = br_dec16be(
|
||||
cc->store + x + VERSION_OFF);
|
||||
params->cipher_suite = br_dec16be(
|
||||
cc->store + x + CIPHER_SUITE_OFF);
|
||||
memcpy(params->master_secret,
|
||||
cc->store + x + MASTER_SECRET_OFF,
|
||||
MASTER_SECRET_LEN);
|
||||
if (x != cc->head) {
|
||||
/*
|
||||
* Found node is not at list head, so move
|
||||
* it to the head.
|
||||
*/
|
||||
uint32_t p, n;
|
||||
|
||||
p = get_prev(cc, x);
|
||||
n = get_next(cc, x);
|
||||
set_next(cc, p, n);
|
||||
if (n == ADDR_NULL) {
|
||||
cc->tail = p;
|
||||
} else {
|
||||
set_prev(cc, n, p);
|
||||
}
|
||||
set_prev(cc, cc->head, x);
|
||||
set_next(cc, x, cc->head);
|
||||
set_prev(cc, x, ADDR_NULL);
|
||||
cc->head = x;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const br_ssl_session_cache_class lru_class = {
|
||||
sizeof(br_ssl_session_cache_lru),
|
||||
&lru_save,
|
||||
&lru_load
|
||||
};
|
||||
|
||||
/* see inner.h */
|
||||
void
|
||||
br_ssl_session_cache_lru_init(br_ssl_session_cache_lru *cc,
|
||||
unsigned char *store, size_t store_len)
|
||||
{
|
||||
cc->vtable = &lru_class;
|
||||
cc->store = store;
|
||||
cc->store_len = store_len;
|
||||
cc->store_ptr = 0;
|
||||
cc->init_done = 0;
|
||||
cc->head = ADDR_NULL;
|
||||
cc->tail = ADDR_NULL;
|
||||
cc->root = ADDR_NULL;
|
||||
}
|
||||
440
src/ssl/ssl_rec_cbc.c
Normal file
440
src/ssl/ssl_rec_cbc.c
Normal file
|
|
@ -0,0 +1,440 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "inner.h"
|
||||
|
||||
static void
|
||||
in_cbc_init(br_sslrec_in_cbc_context *cc,
|
||||
const br_block_cbcdec_class *bc_impl,
|
||||
const void *bc_key, size_t bc_key_len,
|
||||
const br_hash_class *dig_impl,
|
||||
const void *mac_key, size_t mac_key_len, size_t mac_out_len,
|
||||
const void *iv)
|
||||
{
|
||||
cc->vtable = &br_sslrec_in_cbc_vtable;
|
||||
cc->seq = 0;
|
||||
bc_impl->init(&cc->bc.vtable, bc_key, bc_key_len);
|
||||
br_hmac_key_init(&cc->mac, dig_impl, mac_key, mac_key_len);
|
||||
cc->mac_len = mac_out_len;
|
||||
if (iv == NULL) {
|
||||
memset(cc->iv, 0, sizeof cc->iv);
|
||||
cc->explicit_IV = 1;
|
||||
} else {
|
||||
memcpy(cc->iv, iv, bc_impl->block_size);
|
||||
cc->explicit_IV = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
cbc_check_length(const br_sslrec_in_cbc_context *cc, size_t rlen)
|
||||
{
|
||||
/*
|
||||
* Plaintext size: at most 16384 bytes
|
||||
* Padding: at most 256 bytes
|
||||
* MAC: mac_len extra bytes
|
||||
* TLS 1.1+: each record has an explicit IV
|
||||
*
|
||||
* Minimum length includes at least one byte of padding, and the
|
||||
* MAC.
|
||||
*
|
||||
* Total length must be a multiple of the block size.
|
||||
*/
|
||||
size_t blen;
|
||||
size_t min_len, max_len;
|
||||
|
||||
blen = cc->bc.vtable->block_size;
|
||||
min_len = (blen + cc->mac_len) & ~(blen - 1);
|
||||
max_len = (16384 + 256 + cc->mac_len) & ~(blen - 1);
|
||||
if (cc->explicit_IV) {
|
||||
min_len += blen;
|
||||
max_len += blen;
|
||||
}
|
||||
return min_len <= rlen && rlen <= max_len;
|
||||
}
|
||||
|
||||
/*
|
||||
* Rotate array buf[] of length 'len' to the left (towards low indices)
|
||||
* by 'num' bytes if ctl is 1; otherwise, leave it unchanged. This is
|
||||
* constant-time. 'num' MUST be lower than 'len'. 'len' MUST be lower
|
||||
* than or equal to 64.
|
||||
*/
|
||||
static void
|
||||
cond_rotate(uint32_t ctl, unsigned char *buf, size_t len, size_t num)
|
||||
{
|
||||
unsigned char tmp[64];
|
||||
size_t u, v;
|
||||
|
||||
for (u = 0, v = num; u < len; u ++) {
|
||||
tmp[u] = MUX(ctl, buf[v], buf[u]);
|
||||
if (++ v == len) {
|
||||
v = 0;
|
||||
}
|
||||
}
|
||||
memcpy(buf, tmp, len);
|
||||
}
|
||||
|
||||
static unsigned char *
|
||||
cbc_decrypt(br_sslrec_in_cbc_context *cc,
|
||||
int record_type, unsigned version, void *data, size_t *data_len)
|
||||
{
|
||||
/*
|
||||
* We represent all lengths on 32-bit integers, because:
|
||||
* -- SSL record lengths always fit in 32 bits;
|
||||
* -- our constant-time primitives operate on 32-bit integers.
|
||||
*/
|
||||
unsigned char *buf;
|
||||
uint32_t u, v, len, blen, min_len, max_len;
|
||||
uint32_t good, pad_len, rot_count, len_withmac, len_nomac;
|
||||
unsigned char tmp1[64], tmp2[64];
|
||||
int i;
|
||||
br_hmac_context hc;
|
||||
|
||||
buf = data;
|
||||
len = *data_len;
|
||||
blen = cc->bc.vtable->block_size;
|
||||
|
||||
/*
|
||||
* Decrypt data, and skip the explicit IV (if applicable). Note
|
||||
* that the total length is supposed to have been verified by
|
||||
* the caller. If there is an explicit IV, then we actually
|
||||
* "decrypt" it using the implicit IV (from previous record),
|
||||
* which is useless but harmless.
|
||||
*/
|
||||
cc->bc.vtable->run(&cc->bc.vtable, cc->iv, data, len);
|
||||
if (cc->explicit_IV) {
|
||||
buf += blen;
|
||||
len -= blen;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compute minimum and maximum length of plaintext + MAC. These
|
||||
* lengths can be inferred from the outside: they are not secret.
|
||||
*/
|
||||
min_len = (cc->mac_len + 256 < len) ? len - 256 : cc->mac_len;
|
||||
max_len = len - 1;
|
||||
|
||||
/*
|
||||
* Use the last decrypted byte to compute the actual payload
|
||||
* length. Take care not to underflow (we use unsigned types).
|
||||
*/
|
||||
pad_len = buf[max_len];
|
||||
good = LE(pad_len, (uint32_t)(max_len - min_len));
|
||||
len = MUX(good, (uint32_t)(max_len - pad_len), min_len);
|
||||
|
||||
/*
|
||||
* Check padding contents: all padding bytes must be equal to
|
||||
* the value of pad_len.
|
||||
*/
|
||||
for (u = min_len; u < max_len; u ++) {
|
||||
good &= LT(u, len) | EQ(buf[u], pad_len);
|
||||
}
|
||||
|
||||
/*
|
||||
* Extract the MAC value. This is done in one pass, but results
|
||||
* in a "rotated" MAC value depending on where it actually
|
||||
* occurs. The 'rot_count' value is set to the offset of the
|
||||
* first MAC byte within tmp1[].
|
||||
*
|
||||
* min_len and max_len are also adjusted to the minimum and
|
||||
* maximum lengths of the plaintext alone (without the MAC).
|
||||
*/
|
||||
len_withmac = (uint32_t)len;
|
||||
len_nomac = len_withmac - cc->mac_len;
|
||||
min_len -= cc->mac_len;
|
||||
rot_count = 0;
|
||||
memset(tmp1, 0, cc->mac_len);
|
||||
v = 0;
|
||||
for (u = min_len; u < max_len; u ++) {
|
||||
tmp1[v] |= MUX(GE(u, len_nomac) & LT(u, len_withmac),
|
||||
buf[u], 0x00);
|
||||
rot_count = MUX(EQ(u, len_nomac), v, rot_count);
|
||||
if (++ v == cc->mac_len) {
|
||||
v = 0;
|
||||
}
|
||||
}
|
||||
max_len -= cc->mac_len;
|
||||
|
||||
/*
|
||||
* Rotate back the MAC value. The loop below does the constant-time
|
||||
* rotation in time n*log n for a MAC output of length n. We assume
|
||||
* that the MAC output length is no more than 64 bytes, so the
|
||||
* rotation count fits on 6 bits.
|
||||
*/
|
||||
for (i = 5; i >= 0; i --) {
|
||||
uint32_t rc;
|
||||
|
||||
rc = (uint32_t)1 << i;
|
||||
cond_rotate(rot_count >> i, tmp1, cc->mac_len, rc);
|
||||
rot_count &= ~rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Recompute the HMAC value. The input is the concatenation of
|
||||
* the sequence number (8 bytes), the record header (5 bytes),
|
||||
* and the payload.
|
||||
*
|
||||
* At that point, min_len is the minimum plaintext length, but
|
||||
* max_len still includes the MAC length.
|
||||
*/
|
||||
br_enc64be(tmp2, cc->seq ++);
|
||||
tmp2[8] = (unsigned char)record_type;
|
||||
br_enc16be(tmp2 + 9, version);
|
||||
br_enc16be(tmp2 + 11, len_nomac);
|
||||
br_hmac_init(&hc, &cc->mac, cc->mac_len);
|
||||
br_hmac_update(&hc, tmp2, 13);
|
||||
br_hmac_outCT(&hc, buf, len_nomac, min_len, max_len, tmp2);
|
||||
|
||||
/*
|
||||
* Compare the extracted and recomputed MAC values.
|
||||
*/
|
||||
for (u = 0; u < cc->mac_len; u ++) {
|
||||
good &= EQ0(tmp1[u] ^ tmp2[u]);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check that the plaintext length is valid. The previous
|
||||
* check was on the encrypted length, but the padding may have
|
||||
* turned shorter than expected.
|
||||
*
|
||||
* Once this final test is done, the critical "constant-time"
|
||||
* section ends and we can make conditional jumps again.
|
||||
*/
|
||||
good &= LE(len_nomac, 16384);
|
||||
|
||||
if (!good) {
|
||||
return 0;
|
||||
}
|
||||
*data_len = len_nomac;
|
||||
return buf;
|
||||
}
|
||||
|
||||
/* see bearssl_ssl.h */
|
||||
const br_sslrec_in_cbc_class br_sslrec_in_cbc_vtable = {
|
||||
{
|
||||
sizeof(br_sslrec_in_cbc_context),
|
||||
(int (*)(const br_sslrec_in_class *const *, size_t))
|
||||
&cbc_check_length,
|
||||
(unsigned char *(*)(const br_sslrec_in_class **,
|
||||
int, unsigned, void *, size_t *))
|
||||
&cbc_decrypt
|
||||
},
|
||||
(void (*)(const br_sslrec_in_cbc_class **,
|
||||
const br_block_cbcdec_class *, const void *, size_t,
|
||||
const br_hash_class *, const void *, size_t, size_t,
|
||||
const void *))
|
||||
&in_cbc_init
|
||||
};
|
||||
|
||||
/*
|
||||
* For CBC output:
|
||||
*
|
||||
* -- With TLS 1.1+, there is an explicit IV. Generation method uses
|
||||
* HMAC, computed over the current sequence number, and the current MAC
|
||||
* key. The resulting value is truncated to the size of a block, and
|
||||
* added at the head of the plaintext; it will get encrypted along with
|
||||
* the data. This custom generation mechanism is "safe" under the
|
||||
* assumption that HMAC behaves like a random oracle; since the MAC for
|
||||
* a record is computed over the concatenation of the sequence number,
|
||||
* the record header and the plaintext, the HMAC-for-IV will not collide
|
||||
* with the normal HMAC.
|
||||
*
|
||||
* -- With TLS 1.0, for application data, we want to enforce a 1/n-1
|
||||
* split, as a countermeasure against chosen-plaintext attacks. We thus
|
||||
* need to leave some room in the buffer for that extra record.
|
||||
*/
|
||||
|
||||
static void
|
||||
out_cbc_init(br_sslrec_out_cbc_context *cc,
|
||||
const br_block_cbcenc_class *bc_impl,
|
||||
const void *bc_key, size_t bc_key_len,
|
||||
const br_hash_class *dig_impl,
|
||||
const void *mac_key, size_t mac_key_len, size_t mac_out_len,
|
||||
const void *iv)
|
||||
{
|
||||
cc->vtable = &br_sslrec_out_cbc_vtable;
|
||||
cc->seq = 0;
|
||||
bc_impl->init(&cc->bc.vtable, bc_key, bc_key_len);
|
||||
br_hmac_key_init(&cc->mac, dig_impl, mac_key, mac_key_len);
|
||||
cc->mac_len = mac_out_len;
|
||||
if (iv == NULL) {
|
||||
memset(cc->iv, 0, sizeof cc->iv);
|
||||
cc->explicit_IV = 1;
|
||||
} else {
|
||||
memcpy(cc->iv, iv, bc_impl->block_size);
|
||||
cc->explicit_IV = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
cbc_max_plaintext(const br_sslrec_out_cbc_context *cc,
|
||||
size_t *start, size_t *end)
|
||||
{
|
||||
size_t blen, len;
|
||||
|
||||
blen = cc->bc.vtable->block_size;
|
||||
if (cc->explicit_IV) {
|
||||
*start += blen;
|
||||
} else {
|
||||
*start += 4 + ((cc->mac_len + blen + 1) & ~(blen - 1));
|
||||
}
|
||||
len = (*end - *start) & ~(blen - 1);
|
||||
len -= 1 + cc->mac_len;
|
||||
if (len > 16384) {
|
||||
len = 16384;
|
||||
}
|
||||
*end = *start + len;
|
||||
}
|
||||
|
||||
static unsigned char *
|
||||
cbc_encrypt(br_sslrec_out_cbc_context *cc,
|
||||
int record_type, unsigned version, void *data, size_t *data_len)
|
||||
{
|
||||
unsigned char *buf, *rbuf;
|
||||
size_t len, blen, plen;
|
||||
unsigned char tmp[13];
|
||||
br_hmac_context hc;
|
||||
|
||||
buf = data;
|
||||
len = *data_len;
|
||||
blen = cc->bc.vtable->block_size;
|
||||
|
||||
/*
|
||||
* If using TLS 1.0, with more than one byte of plaintext, and
|
||||
* the record is application data, then we need to compute
|
||||
* a "split". We do not perform the split on other record types
|
||||
* because it turned out that some existing, deployed
|
||||
* implementations of SSL/TLS do not tolerate the splitting of
|
||||
* some message types (in particular the Finished message).
|
||||
*
|
||||
* If using TLS 1.1+, then there is an explicit IV. We produce
|
||||
* that IV by adding an extra initial plaintext block, whose
|
||||
* value is computed with HMAC over the record sequence number.
|
||||
*/
|
||||
if (cc->explicit_IV) {
|
||||
/*
|
||||
* We use here the fact that all the HMAC variants we
|
||||
* support can produce at least 16 bytes, while all the
|
||||
* block ciphers we support have blocks of no more than
|
||||
* 16 bytes. Thus, we can always truncate the HMAC output
|
||||
* down to the block size.
|
||||
*/
|
||||
br_enc64be(tmp, cc->seq);
|
||||
br_hmac_init(&hc, &cc->mac, blen);
|
||||
br_hmac_update(&hc, tmp, 8);
|
||||
br_hmac_out(&hc, buf - blen);
|
||||
rbuf = buf - blen - 5;
|
||||
} else {
|
||||
if (len > 1 && record_type == BR_SSL_APPLICATION_DATA) {
|
||||
/*
|
||||
* To do the split, we use a recursive invocation;
|
||||
* since we only give one byte to the inner call,
|
||||
* the recursion stops there.
|
||||
*
|
||||
* We need to compute the exact size of the extra
|
||||
* record, so that the two resulting records end up
|
||||
* being sequential in RAM.
|
||||
*
|
||||
* We use here the fact that cbc_max_plaintext()
|
||||
* adjusted the start offset to leave room for the
|
||||
* initial fragment.
|
||||
*/
|
||||
size_t xlen;
|
||||
|
||||
rbuf = buf - 4
|
||||
- ((cc->mac_len + blen + 1) & ~(blen - 1));
|
||||
rbuf[0] = buf[0];
|
||||
xlen = 1;
|
||||
rbuf = cbc_encrypt(cc, record_type,
|
||||
version, rbuf, &xlen);
|
||||
buf ++;
|
||||
len --;
|
||||
} else {
|
||||
rbuf = buf - 5;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Compute MAC.
|
||||
*/
|
||||
br_enc64be(tmp, cc->seq ++);
|
||||
tmp[8] = record_type;
|
||||
br_enc16be(tmp + 9, version);
|
||||
br_enc16be(tmp + 11, len);
|
||||
br_hmac_init(&hc, &cc->mac, cc->mac_len);
|
||||
br_hmac_update(&hc, tmp, 13);
|
||||
br_hmac_update(&hc, buf, len);
|
||||
br_hmac_out(&hc, buf + len);
|
||||
len += cc->mac_len;
|
||||
|
||||
/*
|
||||
* Add padding.
|
||||
*/
|
||||
plen = blen - (len & (blen - 1));
|
||||
memset(buf + len, (unsigned)plen - 1, plen);
|
||||
len += plen;
|
||||
|
||||
/*
|
||||
* If an explicit IV is used, the corresponding extra block was
|
||||
* already put in place earlier; we just have to account for it
|
||||
* here.
|
||||
*/
|
||||
if (cc->explicit_IV) {
|
||||
buf -= blen;
|
||||
len += blen;
|
||||
}
|
||||
|
||||
/*
|
||||
* Encrypt the whole thing. If there is an explicit IV, we also
|
||||
* encrypt it, which is fine (encryption of a uniformly random
|
||||
* block is still a uniformly random block).
|
||||
*/
|
||||
cc->bc.vtable->run(&cc->bc.vtable, cc->iv, buf, len);
|
||||
|
||||
/*
|
||||
* Add the header and return.
|
||||
*/
|
||||
buf[-5] = record_type;
|
||||
br_enc16be(buf - 4, version);
|
||||
br_enc16be(buf - 2, len);
|
||||
*data_len = (size_t)((buf + len) - rbuf);
|
||||
return rbuf;
|
||||
}
|
||||
|
||||
/* see bearssl_ssl.h */
|
||||
const br_sslrec_out_cbc_class br_sslrec_out_cbc_vtable = {
|
||||
{
|
||||
sizeof(br_sslrec_out_cbc_context),
|
||||
(void (*)(const br_sslrec_out_class *const *,
|
||||
size_t *, size_t *))
|
||||
&cbc_max_plaintext,
|
||||
(unsigned char *(*)(const br_sslrec_out_class **,
|
||||
int, unsigned, void *, size_t *))
|
||||
&cbc_encrypt
|
||||
},
|
||||
(void (*)(const br_sslrec_out_cbc_class **,
|
||||
const br_block_cbcenc_class *, const void *, size_t,
|
||||
const br_hash_class *, const void *, size_t, size_t,
|
||||
const void *))
|
||||
&out_cbc_init
|
||||
};
|
||||
235
src/ssl/ssl_rec_gcm.c
Normal file
235
src/ssl/ssl_rec_gcm.c
Normal file
|
|
@ -0,0 +1,235 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "inner.h"
|
||||
|
||||
/*
|
||||
* GCM initialisation. This does everything except setting the vtable,
|
||||
* which depends on whether this is a context for encrypting or for
|
||||
* decrypting.
|
||||
*/
|
||||
static void
|
||||
gen_gcm_init(br_sslrec_gcm_context *cc,
|
||||
const br_block_ctr_class *bc_impl,
|
||||
const void *key, size_t key_len,
|
||||
br_ghash gh_impl,
|
||||
const void *iv)
|
||||
{
|
||||
unsigned char tmp[12];
|
||||
|
||||
cc->seq = 0;
|
||||
bc_impl->init(&cc->bc.vtable, key, key_len);
|
||||
cc->gh = gh_impl;
|
||||
memcpy(cc->iv, iv, sizeof cc->iv);
|
||||
memset(cc->h, 0, sizeof cc->h);
|
||||
memset(tmp, 0, sizeof tmp);
|
||||
bc_impl->run(&cc->bc.vtable, tmp, 0, cc->h, sizeof cc->h);
|
||||
}
|
||||
|
||||
static void
|
||||
in_gcm_init(br_sslrec_gcm_context *cc,
|
||||
const br_block_ctr_class *bc_impl,
|
||||
const void *key, size_t key_len,
|
||||
br_ghash gh_impl,
|
||||
const void *iv)
|
||||
{
|
||||
cc->vtable.in = &br_sslrec_in_gcm_vtable;
|
||||
gen_gcm_init(cc, bc_impl, key, key_len, gh_impl, iv);
|
||||
}
|
||||
|
||||
static int
|
||||
gcm_check_length(const br_sslrec_gcm_context *cc, size_t rlen)
|
||||
{
|
||||
/*
|
||||
* GCM adds a fixed overhead:
|
||||
* 8 bytes for the nonce_explicit (before the ciphertext)
|
||||
* 16 bytes for the authentication tag (after the ciphertext)
|
||||
*/
|
||||
(void)cc;
|
||||
return rlen >= 24 && rlen <= (16384 + rlen);
|
||||
}
|
||||
|
||||
/*
|
||||
* Compute the authentication tag. The value written in 'tag' must still
|
||||
* be CTR-encrypted.
|
||||
*/
|
||||
static void
|
||||
do_tag(br_sslrec_gcm_context *cc,
|
||||
int record_type, unsigned version,
|
||||
void *data, size_t len, void *tag)
|
||||
{
|
||||
unsigned char header[13];
|
||||
unsigned char footer[16];
|
||||
|
||||
/*
|
||||
* Compute authentication tag. Three elements must be injected in
|
||||
* sequence, each possibly 0-padded to reach a length multiple
|
||||
* of the block size: the 13-byte header (sequence number, record
|
||||
* type, protocol version, record length), the cipher text, and
|
||||
* the word containing the encodings of the bit lengths of the two
|
||||
* other elements.
|
||||
*/
|
||||
br_enc64be(header, cc->seq ++);
|
||||
header[8] = (unsigned char)record_type;
|
||||
br_enc16be(header + 9, version);
|
||||
br_enc16be(header + 11, len);
|
||||
br_enc64be(footer, (uint64_t)(sizeof header) << 3);
|
||||
br_enc64be(footer + 8, (uint64_t)len << 3);
|
||||
memset(tag, 0, 16);
|
||||
cc->gh(tag, cc->h, header, sizeof header);
|
||||
cc->gh(tag, cc->h, data, len);
|
||||
cc->gh(tag, cc->h, footer, sizeof footer);
|
||||
}
|
||||
|
||||
/*
|
||||
* Do CTR encryption. This also does CTR encryption of a single block at
|
||||
* address 'xortag' with the counter value appropriate for the final
|
||||
* processing of the authentication tag.
|
||||
*/
|
||||
static void
|
||||
do_ctr(br_sslrec_gcm_context *cc, const void *nonce, void *data, size_t len,
|
||||
void *xortag)
|
||||
{
|
||||
unsigned char iv[12];
|
||||
|
||||
memcpy(iv, cc->iv, 4);
|
||||
memcpy(iv + 4, nonce, 8);
|
||||
cc->bc.vtable->run(&cc->bc.vtable, iv, 2, data, len);
|
||||
cc->bc.vtable->run(&cc->bc.vtable, iv, 1, xortag, 16);
|
||||
}
|
||||
|
||||
static unsigned char *
|
||||
gcm_decrypt(br_sslrec_gcm_context *cc,
|
||||
int record_type, unsigned version, void *data, size_t *data_len)
|
||||
{
|
||||
unsigned char *buf;
|
||||
size_t len, u;
|
||||
uint32_t bad;
|
||||
unsigned char tag[16];
|
||||
|
||||
buf = (unsigned char *)data + 8;
|
||||
len = *data_len - 24;
|
||||
do_tag(cc, record_type, version, buf, len, tag);
|
||||
do_ctr(cc, data, buf, len, tag);
|
||||
|
||||
/*
|
||||
* Compare the computed tag with the value from the record. It
|
||||
* is possibly useless to do a constant-time comparison here,
|
||||
* but it does not hurt.
|
||||
*/
|
||||
bad = 0;
|
||||
for (u = 0; u < 16; u ++) {
|
||||
bad |= tag[u] ^ buf[len + u];
|
||||
}
|
||||
if (bad) {
|
||||
return NULL;
|
||||
}
|
||||
*data_len = len;
|
||||
return buf;
|
||||
}
|
||||
|
||||
/* see bearssl_ssl.h */
|
||||
const br_sslrec_in_gcm_class br_sslrec_in_gcm_vtable = {
|
||||
{
|
||||
sizeof(br_sslrec_gcm_context),
|
||||
(int (*)(const br_sslrec_in_class *const *, size_t))
|
||||
&gcm_check_length,
|
||||
(unsigned char *(*)(const br_sslrec_in_class **,
|
||||
int, unsigned, void *, size_t *))
|
||||
&gcm_decrypt
|
||||
},
|
||||
(void (*)(const br_sslrec_in_gcm_class **,
|
||||
const br_block_ctr_class *, const void *, size_t,
|
||||
br_ghash, const void *))
|
||||
&in_gcm_init
|
||||
};
|
||||
|
||||
static void
|
||||
out_gcm_init(br_sslrec_gcm_context *cc,
|
||||
const br_block_ctr_class *bc_impl,
|
||||
const void *key, size_t key_len,
|
||||
br_ghash gh_impl,
|
||||
const void *iv)
|
||||
{
|
||||
cc->vtable.out = &br_sslrec_out_gcm_vtable;
|
||||
gen_gcm_init(cc, bc_impl, key, key_len, gh_impl, iv);
|
||||
}
|
||||
|
||||
static void
|
||||
gcm_max_plaintext(const br_sslrec_gcm_context *cc,
|
||||
size_t *start, size_t *end)
|
||||
{
|
||||
size_t len;
|
||||
|
||||
(void)cc;
|
||||
*start += 8;
|
||||
len = *end - *start - 16;
|
||||
if (len > 16384) {
|
||||
len = 16384;
|
||||
}
|
||||
*end = *start + len;
|
||||
}
|
||||
|
||||
static unsigned char *
|
||||
gcm_encrypt(br_sslrec_gcm_context *cc,
|
||||
int record_type, unsigned version, void *data, size_t *data_len)
|
||||
{
|
||||
unsigned char *buf;
|
||||
size_t u, len;
|
||||
unsigned char tmp[16];
|
||||
|
||||
buf = (unsigned char *)data;
|
||||
len = *data_len;
|
||||
memset(tmp, 0, sizeof tmp);
|
||||
br_enc64be(buf - 8, cc->seq);
|
||||
do_ctr(cc, buf - 8, buf, len, tmp);
|
||||
do_tag(cc, record_type, version, buf, len, buf + len);
|
||||
for (u = 0; u < 16; u ++) {
|
||||
buf[len + u] ^= tmp[u];
|
||||
}
|
||||
len += 24;
|
||||
buf -= 13;
|
||||
buf[0] = (unsigned char)record_type;
|
||||
br_enc16be(buf + 1, version);
|
||||
br_enc16be(buf + 3, len);
|
||||
*data_len = len + 5;
|
||||
return buf;
|
||||
}
|
||||
|
||||
/* see bearssl_ssl.h */
|
||||
const br_sslrec_out_gcm_class br_sslrec_out_gcm_vtable = {
|
||||
{
|
||||
sizeof(br_sslrec_gcm_context),
|
||||
(void (*)(const br_sslrec_out_class *const *,
|
||||
size_t *, size_t *))
|
||||
&gcm_max_plaintext,
|
||||
(unsigned char *(*)(const br_sslrec_out_class **,
|
||||
int, unsigned, void *, size_t *))
|
||||
&gcm_encrypt
|
||||
},
|
||||
(void (*)(const br_sslrec_out_gcm_class **,
|
||||
const br_block_ctr_class *, const void *, size_t,
|
||||
br_ghash, const void *))
|
||||
&out_gcm_init
|
||||
};
|
||||
52
src/ssl/ssl_server.c
Normal file
52
src/ssl/ssl_server.c
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "inner.h"
|
||||
|
||||
/* see bearssl_ssl.h */
|
||||
void
|
||||
br_ssl_server_zero(br_ssl_server_context *cc)
|
||||
{
|
||||
/*
|
||||
* For really standard C, we should explicitly set to NULL all
|
||||
* pointers, and 0 all other fields. However, on all our target
|
||||
* architectures, a direct memset() will work, be faster, and
|
||||
* use a lot less code.
|
||||
*/
|
||||
memset(cc, 0, sizeof *cc);
|
||||
}
|
||||
|
||||
/* see bearssl_ssl.h */
|
||||
int
|
||||
br_ssl_server_reset(br_ssl_server_context *cc)
|
||||
{
|
||||
br_ssl_engine_set_buffer(&cc->eng, NULL, 0, 0);
|
||||
if (!br_ssl_engine_init_rand(&cc->eng)) {
|
||||
return 0;
|
||||
}
|
||||
cc->eng.reneg = 0;
|
||||
br_ssl_engine_hs_reset(&cc->eng,
|
||||
br_ssl_hs_server_init_main, br_ssl_hs_server_run);
|
||||
return br_ssl_engine_last_error(&cc->eng) == BR_ERR_OK;
|
||||
}
|
||||
165
src/ssl/ssl_server_full_ec.c
Normal file
165
src/ssl/ssl_server_full_ec.c
Normal file
|
|
@ -0,0 +1,165 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "inner.h"
|
||||
|
||||
/* see bearssl_ssl.h */
|
||||
void
|
||||
br_ssl_server_init_full_ec(br_ssl_server_context *cc,
|
||||
const br_x509_certificate *chain, size_t chain_len,
|
||||
unsigned cert_issuer_key_type, const br_ec_private_key *sk)
|
||||
{
|
||||
/*
|
||||
* The "full" profile supports all implemented cipher suites.
|
||||
*
|
||||
* Rationale for suite order, from most important to least
|
||||
* important rule:
|
||||
*
|
||||
* -- Don't use 3DES if AES is available.
|
||||
* -- Try to have Forward Secrecy (ECDHE suite) if possible.
|
||||
* -- GCM is better than CBC.
|
||||
* -- AES-128 is preferred over AES-256 (AES-128 is already
|
||||
* strong enough, and AES-256 is 40% more expensive).
|
||||
*
|
||||
* Note that for ECDH suites, the list will be automatically
|
||||
* filtered based on the issuing CA key type.
|
||||
*/
|
||||
static const uint16_t suites[] = {
|
||||
BR_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
|
||||
BR_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
|
||||
BR_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
|
||||
BR_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,
|
||||
BR_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
|
||||
BR_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
|
||||
BR_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256,
|
||||
BR_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256,
|
||||
BR_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384,
|
||||
BR_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384,
|
||||
BR_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256,
|
||||
BR_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256,
|
||||
BR_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384,
|
||||
BR_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384,
|
||||
BR_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,
|
||||
BR_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA,
|
||||
BR_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA,
|
||||
BR_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA,
|
||||
BR_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
|
||||
BR_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA,
|
||||
BR_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA
|
||||
};
|
||||
|
||||
/*
|
||||
* All hash functions are activated.
|
||||
* Note: the X.509 validation engine will nonetheless refuse to
|
||||
* validate signatures that use MD5 as hash function.
|
||||
*/
|
||||
static const br_hash_class *hashes[] = {
|
||||
&br_md5_vtable,
|
||||
&br_sha1_vtable,
|
||||
&br_sha224_vtable,
|
||||
&br_sha256_vtable,
|
||||
&br_sha384_vtable,
|
||||
&br_sha512_vtable
|
||||
};
|
||||
|
||||
int id;
|
||||
|
||||
/*
|
||||
* Reset server context and set supported versions from TLS-1.0
|
||||
* to TLS-1.2 (inclusive).
|
||||
*/
|
||||
br_ssl_server_zero(cc);
|
||||
br_ssl_engine_set_versions(&cc->eng, BR_TLS10, BR_TLS12);
|
||||
|
||||
/*
|
||||
* Set suites and elliptic curve implementation (for ECDHE).
|
||||
*/
|
||||
br_ssl_engine_set_suites(&cc->eng, suites,
|
||||
(sizeof suites) / (sizeof suites[0]));
|
||||
br_ssl_engine_set_ec(&cc->eng, &br_ec_prime_i31);
|
||||
|
||||
/*
|
||||
* Set the "server policy": handler for the certificate chain
|
||||
* and private key operations.
|
||||
*/
|
||||
br_ssl_server_set_single_ec(cc, chain, chain_len, sk,
|
||||
BR_KEYTYPE_KEYX | BR_KEYTYPE_SIGN,
|
||||
cert_issuer_key_type,
|
||||
&br_ec_prime_i31, br_ecdsa_i31_sign_asn1);
|
||||
|
||||
/*
|
||||
* Set supported hash functions.
|
||||
*/
|
||||
for (id = br_md5_ID; id <= br_sha512_ID; id ++) {
|
||||
const br_hash_class *hc;
|
||||
|
||||
hc = hashes[id - 1];
|
||||
br_ssl_engine_set_hash(&cc->eng, id, hc);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the PRF implementations.
|
||||
*/
|
||||
br_ssl_engine_set_prf10(&cc->eng, &br_tls10_prf);
|
||||
br_ssl_engine_set_prf_sha256(&cc->eng, &br_tls12_sha256_prf);
|
||||
br_ssl_engine_set_prf_sha384(&cc->eng, &br_tls12_sha384_prf);
|
||||
|
||||
/*
|
||||
* Symmetric encryption. We use the "constant-time"
|
||||
* implementations, which are the safest.
|
||||
*
|
||||
* On architectures detected as "64-bit", use the 64-bit
|
||||
* versions (aes_ct64, ghash_ctmul64).
|
||||
*/
|
||||
#if BR_64
|
||||
br_ssl_engine_set_aes_cbc(&cc->eng,
|
||||
&br_aes_ct64_cbcenc_vtable,
|
||||
&br_aes_ct64_cbcdec_vtable);
|
||||
br_ssl_engine_set_aes_ctr(&cc->eng,
|
||||
&br_aes_ct64_ctr_vtable);
|
||||
br_ssl_engine_set_ghash(&cc->eng,
|
||||
&br_ghash_ctmul64);
|
||||
#else
|
||||
br_ssl_engine_set_aes_cbc(&cc->eng,
|
||||
&br_aes_ct_cbcenc_vtable,
|
||||
&br_aes_ct_cbcdec_vtable);
|
||||
br_ssl_engine_set_aes_ctr(&cc->eng,
|
||||
&br_aes_ct_ctr_vtable);
|
||||
br_ssl_engine_set_ghash(&cc->eng,
|
||||
&br_ghash_ctmul);
|
||||
#endif
|
||||
br_ssl_engine_set_des_cbc(&cc->eng,
|
||||
&br_des_ct_cbcenc_vtable,
|
||||
&br_des_ct_cbcdec_vtable);
|
||||
|
||||
/*
|
||||
* Set the SSL record engines (CBC, GCM).
|
||||
*/
|
||||
br_ssl_engine_set_cbc(&cc->eng,
|
||||
&br_sslrec_in_cbc_vtable,
|
||||
&br_sslrec_out_cbc_vtable);
|
||||
br_ssl_engine_set_gcm(&cc->eng,
|
||||
&br_sslrec_in_gcm_vtable,
|
||||
&br_sslrec_out_gcm_vtable);
|
||||
}
|
||||
154
src/ssl/ssl_server_full_rsa.c
Normal file
154
src/ssl/ssl_server_full_rsa.c
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "inner.h"
|
||||
|
||||
/* see bearssl_ssl.h */
|
||||
void
|
||||
br_ssl_server_init_full_rsa(br_ssl_server_context *cc,
|
||||
const br_x509_certificate *chain, size_t chain_len,
|
||||
const br_rsa_private_key *sk)
|
||||
{
|
||||
/*
|
||||
* The "full" profile supports all implemented cipher suites.
|
||||
*
|
||||
* Rationale for suite order, from most important to least
|
||||
* important rule:
|
||||
*
|
||||
* -- Don't use 3DES if AES is available.
|
||||
* -- Try to have Forward Secrecy (ECDHE suite) if possible.
|
||||
* -- GCM is better than CBC.
|
||||
* -- AES-128 is preferred over AES-256 (AES-128 is already
|
||||
* strong enough, and AES-256 is 40% more expensive).
|
||||
*/
|
||||
static const uint16_t suites[] = {
|
||||
BR_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
|
||||
BR_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
|
||||
BR_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
|
||||
BR_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,
|
||||
BR_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
|
||||
BR_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
|
||||
BR_TLS_RSA_WITH_AES_128_GCM_SHA256,
|
||||
BR_TLS_RSA_WITH_AES_256_GCM_SHA384,
|
||||
BR_TLS_RSA_WITH_AES_128_CBC_SHA256,
|
||||
BR_TLS_RSA_WITH_AES_256_CBC_SHA256,
|
||||
BR_TLS_RSA_WITH_AES_128_CBC_SHA,
|
||||
BR_TLS_RSA_WITH_AES_256_CBC_SHA,
|
||||
BR_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
|
||||
BR_TLS_RSA_WITH_3DES_EDE_CBC_SHA
|
||||
};
|
||||
|
||||
/*
|
||||
* All hash functions are activated.
|
||||
* Note: the X.509 validation engine will nonetheless refuse to
|
||||
* validate signatures that use MD5 as hash function.
|
||||
*/
|
||||
static const br_hash_class *hashes[] = {
|
||||
&br_md5_vtable,
|
||||
&br_sha1_vtable,
|
||||
&br_sha224_vtable,
|
||||
&br_sha256_vtable,
|
||||
&br_sha384_vtable,
|
||||
&br_sha512_vtable
|
||||
};
|
||||
|
||||
int id;
|
||||
|
||||
/*
|
||||
* Reset server context and set supported versions from TLS-1.0
|
||||
* to TLS-1.2 (inclusive).
|
||||
*/
|
||||
br_ssl_server_zero(cc);
|
||||
br_ssl_engine_set_versions(&cc->eng, BR_TLS10, BR_TLS12);
|
||||
|
||||
/*
|
||||
* Set suites and elliptic curve implementation (for ECDHE).
|
||||
*/
|
||||
br_ssl_engine_set_suites(&cc->eng, suites,
|
||||
(sizeof suites) / (sizeof suites[0]));
|
||||
br_ssl_engine_set_ec(&cc->eng, &br_ec_prime_i31);
|
||||
|
||||
/*
|
||||
* Set the "server policy": handler for the certificate chain
|
||||
* and private key operations.
|
||||
*/
|
||||
br_ssl_server_set_single_rsa(cc, chain, chain_len, sk,
|
||||
BR_KEYTYPE_KEYX | BR_KEYTYPE_SIGN,
|
||||
br_rsa_i31_private, br_rsa_i31_pkcs1_sign);
|
||||
|
||||
/*
|
||||
* Set supported hash functions.
|
||||
*/
|
||||
for (id = br_md5_ID; id <= br_sha512_ID; id ++) {
|
||||
const br_hash_class *hc;
|
||||
|
||||
hc = hashes[id - 1];
|
||||
br_ssl_engine_set_hash(&cc->eng, id, hc);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the PRF implementations.
|
||||
*/
|
||||
br_ssl_engine_set_prf10(&cc->eng, &br_tls10_prf);
|
||||
br_ssl_engine_set_prf_sha256(&cc->eng, &br_tls12_sha256_prf);
|
||||
br_ssl_engine_set_prf_sha384(&cc->eng, &br_tls12_sha384_prf);
|
||||
|
||||
/*
|
||||
* Symmetric encryption. We use the "constant-time"
|
||||
* implementations, which are the safest.
|
||||
*
|
||||
* On architectures detected as "64-bit", use the 64-bit
|
||||
* versions (aes_ct64, ghash_ctmul64).
|
||||
*/
|
||||
#if BR_64
|
||||
br_ssl_engine_set_aes_cbc(&cc->eng,
|
||||
&br_aes_ct64_cbcenc_vtable,
|
||||
&br_aes_ct64_cbcdec_vtable);
|
||||
br_ssl_engine_set_aes_ctr(&cc->eng,
|
||||
&br_aes_ct64_ctr_vtable);
|
||||
br_ssl_engine_set_ghash(&cc->eng,
|
||||
&br_ghash_ctmul64);
|
||||
#else
|
||||
br_ssl_engine_set_aes_cbc(&cc->eng,
|
||||
&br_aes_ct_cbcenc_vtable,
|
||||
&br_aes_ct_cbcdec_vtable);
|
||||
br_ssl_engine_set_aes_ctr(&cc->eng,
|
||||
&br_aes_ct_ctr_vtable);
|
||||
br_ssl_engine_set_ghash(&cc->eng,
|
||||
&br_ghash_ctmul);
|
||||
#endif
|
||||
br_ssl_engine_set_des_cbc(&cc->eng,
|
||||
&br_des_ct_cbcenc_vtable,
|
||||
&br_des_ct_cbcdec_vtable);
|
||||
|
||||
/*
|
||||
* Set the SSL record engines (CBC, GCM).
|
||||
*/
|
||||
br_ssl_engine_set_cbc(&cc->eng,
|
||||
&br_sslrec_in_cbc_vtable,
|
||||
&br_sslrec_out_cbc_vtable);
|
||||
br_ssl_engine_set_gcm(&cc->eng,
|
||||
&br_sslrec_in_gcm_vtable,
|
||||
&br_sslrec_out_gcm_vtable);
|
||||
}
|
||||
92
src/ssl/ssl_server_mine2g.c
Normal file
92
src/ssl/ssl_server_mine2g.c
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "inner.h"
|
||||
|
||||
/* see bearssl_ssl.h */
|
||||
void
|
||||
br_ssl_server_init_mine2g(br_ssl_server_context *cc,
|
||||
const br_x509_certificate *chain, size_t chain_len,
|
||||
const br_rsa_private_key *sk)
|
||||
{
|
||||
static const uint16_t suites[] = {
|
||||
BR_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
|
||||
};
|
||||
|
||||
/*
|
||||
* Reset server context and set supported versions to TLS-1.2 (only).
|
||||
*/
|
||||
br_ssl_server_zero(cc);
|
||||
br_ssl_engine_set_versions(&cc->eng, BR_TLS12, BR_TLS12);
|
||||
|
||||
/*
|
||||
* Set suites and elliptic curve implementation (for ECDHE).
|
||||
*/
|
||||
br_ssl_engine_set_suites(&cc->eng, suites,
|
||||
(sizeof suites) / (sizeof suites[0]));
|
||||
br_ssl_engine_set_ec(&cc->eng, &br_ec_prime_i31);
|
||||
|
||||
/*
|
||||
* Set the "server policy": handler for the certificate chain
|
||||
* and private key operations.
|
||||
*/
|
||||
br_ssl_server_set_single_rsa(cc, chain, chain_len, sk,
|
||||
BR_KEYTYPE_SIGN, 0, br_rsa_i31_pkcs1_sign);
|
||||
|
||||
/*
|
||||
* Set supported hash functions.
|
||||
*/
|
||||
br_ssl_engine_set_hash(&cc->eng, br_sha256_ID, &br_sha256_vtable);
|
||||
|
||||
/*
|
||||
* Set the PRF implementations.
|
||||
*/
|
||||
br_ssl_engine_set_prf_sha256(&cc->eng, &br_tls12_sha256_prf);
|
||||
|
||||
/*
|
||||
* Symmetric encryption. We use the "constant-time"
|
||||
* implementations, which are the safest.
|
||||
*
|
||||
* On architectures detected as "64-bit", use the 64-bit
|
||||
* versions (aes_ct64, ghash_ctmul64).
|
||||
*/
|
||||
#if BR_64
|
||||
br_ssl_engine_set_aes_ctr(&cc->eng,
|
||||
&br_aes_ct64_ctr_vtable);
|
||||
br_ssl_engine_set_ghash(&cc->eng,
|
||||
&br_ghash_ctmul64);
|
||||
#else
|
||||
br_ssl_engine_set_aes_ctr(&cc->eng,
|
||||
&br_aes_ct_ctr_vtable);
|
||||
br_ssl_engine_set_ghash(&cc->eng,
|
||||
&br_ghash_ctmul);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Set the SSL record engines (CBC, GCM).
|
||||
*/
|
||||
br_ssl_engine_set_gcm(&cc->eng,
|
||||
&br_sslrec_in_gcm_vtable,
|
||||
&br_sslrec_out_gcm_vtable);
|
||||
}
|
||||
92
src/ssl/ssl_server_minf2g.c
Normal file
92
src/ssl/ssl_server_minf2g.c
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "inner.h"
|
||||
|
||||
/* see bearssl_ssl.h */
|
||||
void
|
||||
br_ssl_server_init_minf2g(br_ssl_server_context *cc,
|
||||
const br_x509_certificate *chain, size_t chain_len,
|
||||
const br_ec_private_key *sk)
|
||||
{
|
||||
static const uint16_t suites[] = {
|
||||
BR_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
|
||||
};
|
||||
|
||||
/*
|
||||
* Reset server context and set supported versions to TLS-1.2 (only).
|
||||
*/
|
||||
br_ssl_server_zero(cc);
|
||||
br_ssl_engine_set_versions(&cc->eng, BR_TLS12, BR_TLS12);
|
||||
|
||||
/*
|
||||
* Set suites and elliptic curve implementation (for ECDHE).
|
||||
*/
|
||||
br_ssl_engine_set_suites(&cc->eng, suites,
|
||||
(sizeof suites) / (sizeof suites[0]));
|
||||
br_ssl_engine_set_ec(&cc->eng, &br_ec_prime_i31);
|
||||
|
||||
/*
|
||||
* Set the "server policy": handler for the certificate chain
|
||||
* and private key operations.
|
||||
*/
|
||||
br_ssl_server_set_single_ec(cc, chain, chain_len, sk,
|
||||
BR_KEYTYPE_SIGN, 0, &br_ec_prime_i31, br_ecdsa_i31_sign_asn1);
|
||||
|
||||
/*
|
||||
* Set supported hash functions.
|
||||
*/
|
||||
br_ssl_engine_set_hash(&cc->eng, br_sha256_ID, &br_sha256_vtable);
|
||||
|
||||
/*
|
||||
* Set the PRF implementations.
|
||||
*/
|
||||
br_ssl_engine_set_prf_sha256(&cc->eng, &br_tls12_sha256_prf);
|
||||
|
||||
/*
|
||||
* Symmetric encryption. We use the "constant-time"
|
||||
* implementations, which are the safest.
|
||||
*
|
||||
* On architectures detected as "64-bit", use the 64-bit
|
||||
* versions (aes_ct64, ghash_ctmul64).
|
||||
*/
|
||||
#if BR_64
|
||||
br_ssl_engine_set_aes_ctr(&cc->eng,
|
||||
&br_aes_ct64_ctr_vtable);
|
||||
br_ssl_engine_set_ghash(&cc->eng,
|
||||
&br_ghash_ctmul64);
|
||||
#else
|
||||
br_ssl_engine_set_aes_ctr(&cc->eng,
|
||||
&br_aes_ct_ctr_vtable);
|
||||
br_ssl_engine_set_ghash(&cc->eng,
|
||||
&br_ghash_ctmul);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Set the SSL record engines (CBC, GCM).
|
||||
*/
|
||||
br_ssl_engine_set_gcm(&cc->eng,
|
||||
&br_sslrec_in_gcm_vtable,
|
||||
&br_sslrec_out_gcm_vtable);
|
||||
}
|
||||
91
src/ssl/ssl_server_minr2g.c
Normal file
91
src/ssl/ssl_server_minr2g.c
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "inner.h"
|
||||
|
||||
/* see bearssl_ssl.h */
|
||||
void
|
||||
br_ssl_server_init_minr2g(br_ssl_server_context *cc,
|
||||
const br_x509_certificate *chain, size_t chain_len,
|
||||
const br_rsa_private_key *sk)
|
||||
{
|
||||
static const uint16_t suites[] = {
|
||||
BR_TLS_RSA_WITH_AES_128_GCM_SHA256
|
||||
};
|
||||
|
||||
/*
|
||||
* Reset server context and set supported versions to TLS-1.2 (only).
|
||||
*/
|
||||
br_ssl_server_zero(cc);
|
||||
br_ssl_engine_set_versions(&cc->eng, BR_TLS12, BR_TLS12);
|
||||
|
||||
/*
|
||||
* Set suites.
|
||||
*/
|
||||
br_ssl_engine_set_suites(&cc->eng, suites,
|
||||
(sizeof suites) / (sizeof suites[0]));
|
||||
|
||||
/*
|
||||
* Set the "server policy": handler for the certificate chain
|
||||
* and private key operations.
|
||||
*/
|
||||
br_ssl_server_set_single_rsa(cc, chain, chain_len, sk,
|
||||
BR_KEYTYPE_KEYX, br_rsa_i31_private, 0);
|
||||
|
||||
/*
|
||||
* Set supported hash functions.
|
||||
*/
|
||||
br_ssl_engine_set_hash(&cc->eng, br_sha256_ID, &br_sha256_vtable);
|
||||
|
||||
/*
|
||||
* Set the PRF implementations.
|
||||
*/
|
||||
br_ssl_engine_set_prf_sha256(&cc->eng, &br_tls12_sha256_prf);
|
||||
|
||||
/*
|
||||
* Symmetric encryption. We use the "constant-time"
|
||||
* implementations, which are the safest.
|
||||
*
|
||||
* On architectures detected as "64-bit", use the 64-bit
|
||||
* versions (aes_ct64, ghash_ctmul64).
|
||||
*/
|
||||
#if BR_64
|
||||
br_ssl_engine_set_aes_ctr(&cc->eng,
|
||||
&br_aes_ct64_ctr_vtable);
|
||||
br_ssl_engine_set_ghash(&cc->eng,
|
||||
&br_ghash_ctmul64);
|
||||
#else
|
||||
br_ssl_engine_set_aes_ctr(&cc->eng,
|
||||
&br_aes_ct_ctr_vtable);
|
||||
br_ssl_engine_set_ghash(&cc->eng,
|
||||
&br_ghash_ctmul);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Set the SSL record engines (CBC, GCM).
|
||||
*/
|
||||
br_ssl_engine_set_gcm(&cc->eng,
|
||||
&br_sslrec_in_gcm_vtable,
|
||||
&br_sslrec_out_gcm_vtable);
|
||||
}
|
||||
91
src/ssl/ssl_server_minu2g.c
Normal file
91
src/ssl/ssl_server_minu2g.c
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "inner.h"
|
||||
|
||||
/* see bearssl_ssl.h */
|
||||
void
|
||||
br_ssl_server_init_minu2g(br_ssl_server_context *cc,
|
||||
const br_x509_certificate *chain, size_t chain_len,
|
||||
const br_ec_private_key *sk)
|
||||
{
|
||||
static const uint16_t suites[] = {
|
||||
BR_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256
|
||||
};
|
||||
|
||||
/*
|
||||
* Reset server context and set supported versions to TLS-1.2 (only).
|
||||
*/
|
||||
br_ssl_server_zero(cc);
|
||||
br_ssl_engine_set_versions(&cc->eng, BR_TLS12, BR_TLS12);
|
||||
|
||||
/*
|
||||
* Set suites.
|
||||
*/
|
||||
br_ssl_engine_set_suites(&cc->eng, suites,
|
||||
(sizeof suites) / (sizeof suites[0]));
|
||||
|
||||
/*
|
||||
* Set the "server policy": handler for the certificate chain
|
||||
* and private key operations.
|
||||
*/
|
||||
br_ssl_server_set_single_ec(cc, chain, chain_len, sk,
|
||||
BR_KEYTYPE_KEYX, BR_KEYTYPE_RSA, &br_ec_prime_i31, 0);
|
||||
|
||||
/*
|
||||
* Set supported hash functions.
|
||||
*/
|
||||
br_ssl_engine_set_hash(&cc->eng, br_sha256_ID, &br_sha256_vtable);
|
||||
|
||||
/*
|
||||
* Set the PRF implementations.
|
||||
*/
|
||||
br_ssl_engine_set_prf_sha256(&cc->eng, &br_tls12_sha256_prf);
|
||||
|
||||
/*
|
||||
* Symmetric encryption. We use the "constant-time"
|
||||
* implementations, which are the safest.
|
||||
*
|
||||
* On architectures detected as "64-bit", use the 64-bit
|
||||
* versions (aes_ct64, ghash_ctmul64).
|
||||
*/
|
||||
#if BR_64
|
||||
br_ssl_engine_set_aes_ctr(&cc->eng,
|
||||
&br_aes_ct64_ctr_vtable);
|
||||
br_ssl_engine_set_ghash(&cc->eng,
|
||||
&br_ghash_ctmul64);
|
||||
#else
|
||||
br_ssl_engine_set_aes_ctr(&cc->eng,
|
||||
&br_aes_ct_ctr_vtable);
|
||||
br_ssl_engine_set_ghash(&cc->eng,
|
||||
&br_ghash_ctmul);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Set the SSL record engines (CBC, GCM).
|
||||
*/
|
||||
br_ssl_engine_set_gcm(&cc->eng,
|
||||
&br_sslrec_in_gcm_vtable,
|
||||
&br_sslrec_out_gcm_vtable);
|
||||
}
|
||||
91
src/ssl/ssl_server_minv2g.c
Normal file
91
src/ssl/ssl_server_minv2g.c
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "inner.h"
|
||||
|
||||
/* see bearssl_ssl.h */
|
||||
void
|
||||
br_ssl_server_init_minv2g(br_ssl_server_context *cc,
|
||||
const br_x509_certificate *chain, size_t chain_len,
|
||||
const br_ec_private_key *sk)
|
||||
{
|
||||
static const uint16_t suites[] = {
|
||||
BR_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256
|
||||
};
|
||||
|
||||
/*
|
||||
* Reset server context and set supported versions to TLS-1.2 (only).
|
||||
*/
|
||||
br_ssl_server_zero(cc);
|
||||
br_ssl_engine_set_versions(&cc->eng, BR_TLS12, BR_TLS12);
|
||||
|
||||
/*
|
||||
* Set suites.
|
||||
*/
|
||||
br_ssl_engine_set_suites(&cc->eng, suites,
|
||||
(sizeof suites) / (sizeof suites[0]));
|
||||
|
||||
/*
|
||||
* Set the "server policy": handler for the certificate chain
|
||||
* and private key operations.
|
||||
*/
|
||||
br_ssl_server_set_single_ec(cc, chain, chain_len, sk,
|
||||
BR_KEYTYPE_KEYX, BR_KEYTYPE_EC, &br_ec_prime_i31, 0);
|
||||
|
||||
/*
|
||||
* Set supported hash functions.
|
||||
*/
|
||||
br_ssl_engine_set_hash(&cc->eng, br_sha256_ID, &br_sha256_vtable);
|
||||
|
||||
/*
|
||||
* Set the PRF implementations.
|
||||
*/
|
||||
br_ssl_engine_set_prf_sha256(&cc->eng, &br_tls12_sha256_prf);
|
||||
|
||||
/*
|
||||
* Symmetric encryption. We use the "constant-time"
|
||||
* implementations, which are the safest.
|
||||
*
|
||||
* On architectures detected as "64-bit", use the 64-bit
|
||||
* versions (aes_ct64, ghash_ctmul64).
|
||||
*/
|
||||
#if BR_64
|
||||
br_ssl_engine_set_aes_ctr(&cc->eng,
|
||||
&br_aes_ct64_ctr_vtable);
|
||||
br_ssl_engine_set_ghash(&cc->eng,
|
||||
&br_ghash_ctmul64);
|
||||
#else
|
||||
br_ssl_engine_set_aes_ctr(&cc->eng,
|
||||
&br_aes_ct_ctr_vtable);
|
||||
br_ssl_engine_set_ghash(&cc->eng,
|
||||
&br_ghash_ctmul);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Set the SSL record engines (CBC, GCM).
|
||||
*/
|
||||
br_ssl_engine_set_gcm(&cc->eng,
|
||||
&br_sslrec_in_gcm_vtable,
|
||||
&br_sslrec_out_gcm_vtable);
|
||||
}
|
||||
132
src/ssl/ssl_single_ec.c
Normal file
132
src/ssl/ssl_single_ec.c
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "inner.h"
|
||||
|
||||
static int
|
||||
se_choose(const br_ssl_server_policy_class **pctx,
|
||||
const br_ssl_server_context *cc,
|
||||
br_ssl_server_choices *choices)
|
||||
{
|
||||
br_ssl_server_policy_ec_context *pc;
|
||||
const br_suite_translated *st;
|
||||
size_t u, st_num;
|
||||
int hash_id;
|
||||
|
||||
pc = (br_ssl_server_policy_ec_context *)pctx;
|
||||
st = br_ssl_server_get_client_suites(cc, &st_num);
|
||||
hash_id = br_ssl_choose_hash(br_ssl_server_get_client_hashes(cc));
|
||||
choices->chain = pc->chain;
|
||||
choices->chain_len = pc->chain_len;
|
||||
for (u = 0; u < st_num; u ++) {
|
||||
unsigned tt;
|
||||
|
||||
tt = st[u][1];
|
||||
switch (tt >> 12) {
|
||||
case BR_SSLKEYX_ECDH_RSA:
|
||||
if ((pc->allowed_usages & BR_KEYTYPE_KEYX) != 0
|
||||
&& pc->cert_issuer_key_type == BR_KEYTYPE_RSA)
|
||||
{
|
||||
choices->cipher_suite = st[u][0];
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
case BR_SSLKEYX_ECDH_ECDSA:
|
||||
if ((pc->allowed_usages & BR_KEYTYPE_KEYX) != 0
|
||||
&& pc->cert_issuer_key_type == BR_KEYTYPE_EC)
|
||||
{
|
||||
choices->cipher_suite = st[u][0];
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
case BR_SSLKEYX_ECDHE_ECDSA:
|
||||
if ((pc->allowed_usages & BR_KEYTYPE_SIGN) != 0
|
||||
&& hash_id != 0)
|
||||
{
|
||||
choices->cipher_suite = st[u][0];
|
||||
choices->hash_id = hash_id;
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
se_do_keyx(const br_ssl_server_policy_class **pctx,
|
||||
unsigned char *data, size_t len)
|
||||
{
|
||||
br_ssl_server_policy_ec_context *pc;
|
||||
|
||||
pc = (br_ssl_server_policy_ec_context *)pctx;
|
||||
return pc->iec->mul(data, len, pc->sk->x, pc->sk->xlen, pc->sk->curve);
|
||||
}
|
||||
|
||||
static size_t
|
||||
se_do_sign(const br_ssl_server_policy_class **pctx,
|
||||
int hash_id, size_t hv_len, unsigned char *data, size_t len)
|
||||
{
|
||||
br_ssl_server_policy_ec_context *pc;
|
||||
unsigned char hv[64];
|
||||
const br_hash_class *hc;
|
||||
|
||||
pc = (br_ssl_server_policy_ec_context *)pctx;
|
||||
hc = br_multihash_getimpl(pc->mhash, hash_id);
|
||||
if (hc == NULL) {
|
||||
return 0;
|
||||
}
|
||||
memcpy(hv, data, hv_len);
|
||||
if (len < 139) {
|
||||
return 0;
|
||||
}
|
||||
return pc->iecdsa(pc->iec, hc, hv, pc->sk, data);
|
||||
}
|
||||
|
||||
static const br_ssl_server_policy_class se_policy_vtable = {
|
||||
sizeof(br_ssl_server_policy_ec_context),
|
||||
se_choose,
|
||||
se_do_keyx,
|
||||
se_do_sign
|
||||
};
|
||||
|
||||
/* see bearssl_ssl.h */
|
||||
void
|
||||
br_ssl_server_set_single_ec(br_ssl_server_context *cc,
|
||||
const br_x509_certificate *chain, size_t chain_len,
|
||||
const br_ec_private_key *sk, unsigned allowed_usages,
|
||||
unsigned cert_issuer_key_type,
|
||||
const br_ec_impl *iec, br_ecdsa_sign iecdsa)
|
||||
{
|
||||
cc->chain_handler.single_ec.vtable = &se_policy_vtable;
|
||||
cc->chain_handler.single_ec.chain = chain;
|
||||
cc->chain_handler.single_ec.chain_len = chain_len;
|
||||
cc->chain_handler.single_ec.sk = sk;
|
||||
cc->chain_handler.single_ec.allowed_usages = allowed_usages;
|
||||
cc->chain_handler.single_ec.cert_issuer_key_type = cert_issuer_key_type;
|
||||
cc->chain_handler.single_ec.mhash = &cc->eng.mhash;
|
||||
cc->chain_handler.single_ec.iec = iec;
|
||||
cc->chain_handler.single_ec.iecdsa = iecdsa;
|
||||
cc->policy_vtable = &cc->chain_handler.single_ec.vtable;
|
||||
}
|
||||
155
src/ssl/ssl_single_rsa.c
Normal file
155
src/ssl/ssl_single_rsa.c
Normal file
|
|
@ -0,0 +1,155 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "inner.h"
|
||||
|
||||
static int
|
||||
sr_choose(const br_ssl_server_policy_class **pctx,
|
||||
const br_ssl_server_context *cc,
|
||||
br_ssl_server_choices *choices)
|
||||
{
|
||||
br_ssl_server_policy_rsa_context *pc;
|
||||
const br_suite_translated *st;
|
||||
size_t u, st_num;
|
||||
int hash_id;
|
||||
|
||||
pc = (br_ssl_server_policy_rsa_context *)pctx;
|
||||
st = br_ssl_server_get_client_suites(cc, &st_num);
|
||||
hash_id = br_ssl_choose_hash(br_ssl_server_get_client_hashes(cc));
|
||||
choices->chain = pc->chain;
|
||||
choices->chain_len = pc->chain_len;
|
||||
for (u = 0; u < st_num; u ++) {
|
||||
unsigned tt;
|
||||
|
||||
tt = st[u][1];
|
||||
switch (tt >> 12) {
|
||||
case BR_SSLKEYX_RSA:
|
||||
if ((pc->allowed_usages & BR_KEYTYPE_KEYX) != 0) {
|
||||
choices->cipher_suite = st[u][0];
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
case BR_SSLKEYX_ECDHE_RSA:
|
||||
if ((pc->allowed_usages & BR_KEYTYPE_SIGN) != 0
|
||||
&& hash_id != 0)
|
||||
{
|
||||
choices->cipher_suite = st[u][0];
|
||||
choices->hash_id = hash_id;
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
sr_do_keyx(const br_ssl_server_policy_class **pctx,
|
||||
unsigned char *data, size_t len)
|
||||
{
|
||||
br_ssl_server_policy_rsa_context *pc;
|
||||
|
||||
pc = (br_ssl_server_policy_rsa_context *)pctx;
|
||||
return br_rsa_ssl_decrypt(pc->irsacore, pc->sk, data, len);
|
||||
}
|
||||
|
||||
/*
|
||||
* OID for hash functions in RSA signatures.
|
||||
*/
|
||||
static const unsigned char HASH_OID_SHA1[] = {
|
||||
0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A
|
||||
};
|
||||
|
||||
static const unsigned char HASH_OID_SHA224[] = {
|
||||
0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04
|
||||
};
|
||||
|
||||
static const unsigned char HASH_OID_SHA256[] = {
|
||||
0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01
|
||||
};
|
||||
|
||||
static const unsigned char HASH_OID_SHA384[] = {
|
||||
0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02
|
||||
};
|
||||
|
||||
static const unsigned char HASH_OID_SHA512[] = {
|
||||
0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03
|
||||
};
|
||||
|
||||
static const unsigned char *HASH_OID[] = {
|
||||
HASH_OID_SHA1,
|
||||
HASH_OID_SHA224,
|
||||
HASH_OID_SHA256,
|
||||
HASH_OID_SHA384,
|
||||
HASH_OID_SHA512
|
||||
};
|
||||
|
||||
static size_t
|
||||
sr_do_sign(const br_ssl_server_policy_class **pctx,
|
||||
int hash_id, size_t hv_len, unsigned char *data, size_t len)
|
||||
{
|
||||
br_ssl_server_policy_rsa_context *pc;
|
||||
unsigned char hv[64];
|
||||
size_t sig_len;
|
||||
const unsigned char *hash_oid;
|
||||
|
||||
pc = (br_ssl_server_policy_rsa_context *)pctx;
|
||||
memcpy(hv, data, hv_len);
|
||||
if (hash_id == 0) {
|
||||
hash_oid = NULL;
|
||||
} else if (hash_id >= 2 && hash_id <= 6) {
|
||||
hash_oid = HASH_OID[hash_id - 2];
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
sig_len = (pc->sk->n_bitlen + 7) >> 3;
|
||||
if (len < sig_len) {
|
||||
return 0;
|
||||
}
|
||||
return pc->irsasign(hash_oid, hv, hv_len, pc->sk, data) ? sig_len : 0;
|
||||
}
|
||||
|
||||
static const br_ssl_server_policy_class sr_policy_vtable = {
|
||||
sizeof(br_ssl_server_policy_rsa_context),
|
||||
sr_choose,
|
||||
sr_do_keyx,
|
||||
sr_do_sign
|
||||
};
|
||||
|
||||
/* see bearssl_ssl.h */
|
||||
void
|
||||
br_ssl_server_set_single_rsa(br_ssl_server_context *cc,
|
||||
const br_x509_certificate *chain, size_t chain_len,
|
||||
const br_rsa_private_key *sk, unsigned allowed_usages,
|
||||
br_rsa_private irsacore, br_rsa_pkcs1_sign irsasign)
|
||||
{
|
||||
cc->chain_handler.single_rsa.vtable = &sr_policy_vtable;
|
||||
cc->chain_handler.single_rsa.chain = chain;
|
||||
cc->chain_handler.single_rsa.chain_len = chain_len;
|
||||
cc->chain_handler.single_rsa.sk = sk;
|
||||
cc->chain_handler.single_rsa.allowed_usages = allowed_usages;
|
||||
cc->chain_handler.single_rsa.irsacore = irsacore;
|
||||
cc->chain_handler.single_rsa.irsasign = irsasign;
|
||||
cc->policy_vtable = &cc->chain_handler.single_rsa.vtable;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue