Initial import.

This commit is contained in:
Thomas Pornin 2016-11-02 19:01:13 -04:00
commit 3210f38e04
292 changed files with 58526 additions and 0 deletions

71
src/ssl/prf.c Normal file
View 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
View 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
View 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
View 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
View 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
View 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

File diff suppressed because it is too large Load diff

46
src/ssl/ssl_hashes.c Normal file
View 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

File diff suppressed because it is too large Load diff

992
src/ssl/ssl_hs_client.t0 Normal file
View 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

File diff suppressed because it is too large Load diff

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

File diff suppressed because it is too large Load diff

255
src/ssl/ssl_io.c Normal file
View 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
View 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
View 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
View 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
View 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;
}

View 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);
}

View 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);
}

View 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);
}

View 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);
}

View 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);
}

View 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);
}

View 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
View 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
View 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;
}