aws / s2n-tls Goto Github PK
View Code? Open in Web Editor NEWAn implementation of the TLS/SSL protocols
Home Page: https://aws.github.io/s2n-tls/usage-guide/
License: Apache License 2.0
An implementation of the TLS/SSL protocols
Home Page: https://aws.github.io/s2n-tls/usage-guide/
License: Apache License 2.0
At present, s2n does not parse certificates; it's desirable to parse the certificates in order to support certificate authentication and validation.
There is currently no example of how to use s2n_connection_free().
Mikko from codenomicon reported occasionally seeing SIGPIPE as an unhandled signal in s2nd. SIGPIPE can be generated when we try to write() to the remote end and the remote end has closed. I don't think that libs2n should mask this; our design is to emulate POSIX read()/write(), but we need s2nd and s2nc to be more tolerant of this. Instead of receiving the signal, it would be better to handle the error in the normal ways, with write() or read() returning negative values (or EOF for read()).
Following patch suppresses SIGPIPE:
index b0268c1..0562d53 100644
--- a/bin/s2nd.c
+++ b/bin/s2nd.c
@@ -22,6 +22,7 @@
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
+#include <signal.h>
#include <stdio.h>
#include <errno.h>
@@ -117,6 +118,11 @@ int main(int argc, const char *argv[])
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
+ if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) {
+ fprintf(stderr, "Error disabling SIGPIPE\n");
+ exit(1);
+ }
+
if ((r = getaddrinfo(argv[1], argv[2], &hints, &ai)) < 0) {
fprintf(stderr, "getaddrinfo error: %s\n", gai_strerror(r));
return -1;
At least implement AES-GCM with TLS1.2. This should be fairly easy.
It would nice if pull requests were automatically built and tested to ensure there are no regressions. I'm not entirely sure how this can be done securely, a pull request may contain arbitrary code, but other projects have figured this out.
If I already have a system-wide installation of updated LibreSSL/OpenSSL libs there's no reason why I shouldn't be able to use them instead of building from scratch into libcrypto-root
. How can I configure the build to use a system-wide path for those libs?
At least in a few places EINTR
is not handled appropriately:
s2n_init
in ./utils/s2n_random.c
for the open
system calls2n_stuffer_alloc_ro_from_file
in ./stuffer/s2n_stuffer_file.c
for the open
system callGUARD(usleep(delay % 1000000));
./bin/echo.c:124:
bytes_read = read(STDIN_FILENO, buffer, bytes_available);
./bin/echo.c:91:
while (poll(readers, 2, -1) > 0) {
echo is a sample application and not too important right?
Also note that the atomicity of reads and writes is weird. Sometimes, reads and writes CANNOT be interrupted and give only partial results but sometimes they can be interrupted in the middle and return less bytes than expected (but not a value of -1.) But I think that you handle that part well enough in most places.
Also, system calls such as read
and write
return a value of type ssize_t
and not int
.
Also, some tests may fail due to this stuff but they're tests so they don't matter too much.
There are a few possibilities to handle this cases.
EINTR
error as appropriate (also remember to handle partial reads and writes)Also note that close
is an absolute pain to handle errors for and is completely fucked from a standardization point of view. I use the following hacky workaround for close
but you may simply want to ignore errors from it.
my_error fd_close(int fd)
{
my_error errnum;
/*
* The state of a file descriptor after close gives an EINTR
* error
* is unspecified by POSIX so this function avoids the problem
* by
* simply blocking all signals.
*/
sigset_t sigset;
/* First use the signal set for the full set */
sigfillset(&sigset);
errnum = pthread_sigmask(SIG_BLOCK, &sigset, &sigset);
if (errnum != 0)
return errnum;
/* Then reuse the signal set for the old set */
if (-1 == close(fd)) {
errnum = errno;
assert(errnum != 0);
} else {
errnum = 0;
}
my_error mask_errnum =
pthread_sigmask(SIG_SETMASK, &sigset, 0);
if (0 == errnum)
errnum = mask_errnum;
return errnum;
}
s2n supports DHE, but it would be great to also support ECDHE for faster negotiation.
For example empty SNI names are not allowed by RFC 3546 but are not rejected.
s2n appears to be perfectly willing to accept version numbers such as 0x0000 in the record layer, and also artificially high ones such as 0x400 or 0xffff. This will lead to interoperability problems with future TLS versions.
s2n callers should be able to specify the maximum record size used for outbound TLS records. Some applications prefer large sizes (which optimize for throughput) and others prefer small sizes (for latency and memory conservation). These sizes should be changeable during the lifetime of a TLS session.
Alternatively, s2n could take responsibility for setting adaptive record sizes.
Additionally; for inbound record sizes it is useful to resize our buffers if the peer is sending small records, as this can conserve memory. Perhaps resize buffers to the min() of the last N records, where N ~= 5-10.
s2n should support OCSP stapling. Implementing HTTP and calling an OSCP endpoint is likely overkill, but it should at least be possible for the caller to periodically provide an OCSP token.
s2n is not intended for use as a TLS client. Setting the mode to S2N_CLIENT should fail except in clear test scenarios.
Tentative idea: require an S2N_INSECURE_CLIENT environment variable be set to enable client mode processing.
If a server vends a 0-length certificate list, towards s2n as a client, it's possible to crash s2n when used as a client. Important note: in s2n, client mode is disabled and this issue is not trigger-able.
The crash occurs inside OpenSSL's RSA_size:
#0 0xb7e9c397 in RSA_size () from /root/s2n/s2n-master/lib/libs2n.so
#1 0xb7e84df9 in s2n_rsa_public_encrypted_size () from /root/s2n/s2n-master/lib/libs2n.so
#2 0xb7e788ef in s2n_client_key_send () from /root/s2n/s2n-master/lib/libs2n.so
#3 0xb7e7ac9e in s2n_negotiate () from /root/s2n/s2n-master/lib/libs2n.so
#4 0x08049b44 in echo ()
#5 0x080494d2 in main ()
Per https://github.com/openssl/openssl/blob/35a1cc90bc1795e8893c11e442790ee7f659fffb/crypto/rsa/rsa_crpt.c#L69 RSA_size() is referencing rsa->n, a bignum which in this case is empty.
What's happening is that we're never calling s2n_asn1der_to_rsa_public_key(), because size_of_all_certificates is 0, and so the inner while loop is never exercised. See https://github.com/awslabs/s2n/blob/e17fd1a4370ec96830cade867879fa07655130c8/tls/s2n_server_cert.c#L58
Issue reported by Mikko from Codenomicon.
The following patch fixes the issue and adds some additional checks in similar code-paths (though none are similarly vulnerable).
diff --git a/crypto/s2n_rsa.c b/crypto/s2n_rsa.c
index 34e2bd7..373bed1 100644
--- a/crypto/s2n_rsa.c
+++ b/crypto/s2n_rsa.c
@@ -95,11 +95,17 @@ int s2n_rsa_private_key_free(struct s2n_rsa_private_key *key)
int s2n_rsa_public_encrypted_size(struct s2n_rsa_public_key *key)
{
+ notnull_check(key->rsa);
+ notnull_check(key->rsa->n);
+
return RSA_size(key->rsa);
}
int s2n_rsa_private_encrypted_size(struct s2n_rsa_private_key *key)
{
+ notnull_check(key->rsa);
+ notnull_check(key->rsa->n);
+
return RSA_size(key->rsa);
}
diff --git a/tls/s2n_client_key_exchange.c b/tls/s2n_client_key_exchange.c
index 6ce1363..a979c51 100644
--- a/tls/s2n_client_key_exchange.c
+++ b/tls/s2n_client_key_exchange.c
@@ -56,6 +56,8 @@ static int s2n_rsa_client_key_recv(struct s2n_connection *conn)
encrypted.size = s2n_stuffer_data_available(in);
encrypted.data = s2n_stuffer_raw_read(in, length);
+ gt_check(encrypted.size, 0);
+
/* Set rsa_failed to 1 if s2n_rsa_decrypt returns anything other than zero */
conn->handshake.rsa_failed = !!s2n_rsa_decrypt(&conn->config->cert_and_key_pairs->private_key, &encrypted, &pms);
diff --git a/tls/s2n_server_cert.c b/tls/s2n_server_cert.c
index 6d1c3fb..ac14713 100644
--- a/tls/s2n_server_cert.c
+++ b/tls/s2n_server_cert.c
@@ -32,17 +32,17 @@ int s2n_server_cert_recv(struct s2n_connection *conn)
GUARD(s2n_stuffer_read_uint24(&conn->handshake.io, &size_of_all_certificates));
- if (size_of_all_certificates > s2n_stuffer_data_available(&conn->handshake.io)) {
+ if (size_of_all_certificates > s2n_stuffer_data_available(&conn->handshake.io) || size_of_all_certificates < 3) {
S2N_ERROR(S2N_ERR_BAD_MESSAGE);
}
- int certificate = 0;
+ int certificate_count = 0;
while (s2n_stuffer_data_available(&conn->handshake.io)) {
uint32_t certificate_size;
GUARD(s2n_stuffer_read_uint24(&conn->handshake.io, &certificate_size));
- if (certificate_size > s2n_stuffer_data_available(&conn->handshake.io)) {
+ if (certificate_size > s2n_stuffer_data_available(&conn->handshake.io) || certificate_size == 0) {
S2N_ERROR(S2N_ERR_BAD_MESSAGE);
}
@@ -52,15 +52,18 @@ int s2n_server_cert_recv(struct s2n_connection *conn)
notnull_check(asn1cert.data);
/* TODO: certificate validation goes here */
+ gt_check(certificate_size, 0);
/* Pull the public key from the first certificate */
- if (certificate == 0) {
+ if (certificate_count == 0) {
GUARD(s2n_asn1der_to_rsa_public_key(&conn->pending.server_rsa_public_key, &asn1cert));
}
- certificate++;
+ certificate_count++;
}
+ gte_check(certificate_count, 1);
+
conn->handshake.next_state = SERVER_HELLO_DONE;
if (conn->status_type == S2N_STATUS_REQUEST_OCSP) {
diff --git a/tls/s2n_server_key_exchange.c b/tls/s2n_server_key_exchange.c
index 330ab2f..ec25dcd 100644
--- a/tls/s2n_server_key_exchange.c
+++ b/tls/s2n_server_key_exchange.c
@@ -102,6 +102,8 @@ static int s2n_ecdhe_server_key_recv(struct s2n_connection *conn)
signature.data = s2n_stuffer_raw_read(in, signature.size);
notnull_check(signature.data);
+ gt_check(signature_length, 0);
+
if (s2n_rsa_verify(&conn->pending.server_rsa_public_key, &signature_hash, &signature) < 0) {
S2N_ERROR(S2N_ERR_BAD_MESSAGE);
}
@@ -191,6 +193,8 @@ static int s2n_dhe_server_key_recv(struct s2n_connection *conn)
signature.data = s2n_stuffer_raw_read(in, signature.size);
notnull_check(signature.data);
+ gt_check(signature_length, 0);
+
if (s2n_rsa_verify(&conn->pending.server_rsa_public_key, &signature_hash, &signature) < 0) {
S2N_ERROR(S2N_ERR_BAD_MESSAGE);
}
Now that we're going to depend on Openssl 1.0.2, it would be nice to have clear instructions on how to build OpenSSL, or LibreSSL, or BoringSSL locally and to use those within s2n. I think we should be able to support each, it looks like they all have the APIs we're using. Additionally, we should consider using libcrypto.a - ie statically linking in libcrypto.
Several functions allocate memory through calls into libcrypto and release it upon successful completion. However the memory is not released under some error conditions which cause
the functions to return early resulting in the memory being leaked.
s2n_dh_compute_shared_secret_as_server() is called by TLS servers every time a client negotiates a session key using integer Diffie-Hellman. It makes one allocation using BN_bin2bn() to hold the client's public key. If the public key is invalid (for instance, all zeroes) the call to DH_compute_key will fail resulting in pub_key memory not being freed. With enough invocations, this could lead to memory exhaustion.
The function s2n_asn1der_to_rsa_public_key() decodes a DER-encoded certificate and extracts an RSA public key from it. Two memory allocations are made in this function by the calls to d2i_X509() and X590_get_pubkey(). Both are correctly released when the function returns. However it can return early under a few error conditions, such as if the certificate does not contain an RSA public key. In these cases the allocations are leaked. At the moment this leak affects only TLS clients since this function is only called on clients.
s2n_pkcs3_to_dh_params() is used to load integer Diffie-Hellman parameters on TLS servers. It makes one allocation using d2i_DHparams() which is not cleaned up if the parameters contain extraneous data. This function is only called during server start-up so it does not appear to be remotely exploitable.
At present s2n supports RSA signatures from certificates, it would be great to also support ECDSA. Realistically this issue depends on implementing #3 (support for multiple certificates) first.
Note: some versions of safari claim to support ECDSA, but do not.
s2n_realloc call mlock. s2n_free does not call munlock. This can lead to an out of memory condition.
According to https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_MRG/1.3/html/Realtime_Reference_Guide/sect-Realtime_Reference_Guide-Memory_allocation-Using_mlock_to_avoid_memory_faults.html munlock is necessary when freeing the locked memory.
According to http://www.freebsd.org/cgi/man.cgi?query=mlock "Unlocking is performed explicitly by munlock() or implicitly by a call to munmap()"
Testing on Ubuntu 14.04.2 LTS continued use of mlock without a corresponding munlock after (can also be done before but I don't think it should) free will not allow the memory to be reused.
At present s2n supports one certificate chain per configuration which effectively limits it to one certificate per listening IP address. It should be possible to provide s2n multiple certificates and to have s2n negotiate which certificate should be used based on 1) certificate name matching, including wildcards 2) signature algorithm type and 3) key agreement type (e.g. DSA, ECDSA, RSA ...).
See awslabs#88 : we should be able to simulate these failures by setting ulimit/setrlimit memory limits artificially low.
Although s2n does not display these patterns, we should add systematic defenses against any future regressions.
It should be possible with various invokations of nm/objdumb/elf-utils to ensure that s2n is remaining ABI stable (at least within reason). Adding systematic regression tests would guard against developer error.
Currently there's example code inlined in https://github.com/awslabs/s2n/blob/master/docs/USAGE-GUIDE.md
It's much the same as the code in the bin directory, but probably is out of date. Would pointing to the bin directory be better?
Some platforms have a getentropy() call for retrieving randomly generated data, Linux has recently added getrandom(), an equivalent call. s2n should support these where available and avoid using /dev/urandom.
SSLv3 is deprecated, use should not be encouraged: https://tools.ietf.org/html/rfc7568
At present s2n operates directly on file descriptors. We have some applications that would prefer to handle the actual network I/O themselves and use "raw" buffers of bytes to interact with s2n.
There are two main possibilities here that we're considering:
RFCs, secure coding guides, etc ...
At present, s2n's CBC validation is not constant time. Instead s2n closes down connections on validation errors, which does make it impractical to mount alert-based timing attacks within the same TLS session. However, validating CBC records in constant time is still desirable. A nanosleep-to-deadline approach has been tested and found to work, but nanosleep is not available on older platforms. A constant-time-CPU-operation approach may be better, but will require testing on several architectures.
s2n should support TLS tickets for session re-use. We should take care to ensure that TLS tickets may only be re-used when all of the TLS negotiation parameters match (e.g. SNI field ... etc). Perhaps use NaCL for encrypting the ticket.
I noticed the following files were missing Apache headers.
./error/s2n_errno.c
./error/s2n_errno.h
./tls/s2n_cbc.c
Happy to add them. I don't have private repos setup for my account, so didn't do a PR.
I've got the change done and 'make' succeeded. Didn't want to commit without your okay.
After building LibreSSL with -fPIC
(cf. issue #94) the build of s2n itself fails during the unit tests. I have seen two different failures after repeated build attempts.
One of them (s2n_client_extensions_test
) is sporadic and mlock()
related and I see a note for that in the USAGE docs so I won't consider that further here.
The other failure that I've seen is s2n_override_openssl_random_test
. This fails on every invocation at test 20:
$ LD_LIBRARY_PATH=../../lib ./s2n_override_openssl_random_test
Running s2n_override_openssl_random_test.c ... FAILED test 20
(mock_called) == (1) is not true (s2n_override_openssl_random_test.c line 114)
Error Message: 'no error'
Relevant lines from the test:
109 EXPECT_EQUAL(mock_called, 0);
110
111 EXPECT_TRUE(DH_generate_key(dh_params.dh) == 1);
112
113 /* Verify that our mock random is called and that over-riding works */
114 EXPECT_EQUAL(mock_called, 1);
from which I gather that mock_openssl_compat_rand()
is not being called.
This can happen if it is actually being called but it returns early if the call to s2n_get_urandom_data()
fails so this is my primary suspect for now.
39 static int mock_openssl_compat_rand(unsigned char *buf, int num)
40 {
41 struct s2n_blob blob = {.data = buf, .size = num };
42
43 int r = s2n_get_urandom_data(&blob);
44 if (r < 0) {
45 return 0;
46 }
47
48 mock_called = 1;
I'm out of time today! Will try to debug more tomorrow.
This line makes me sad, because it can cause some hard-to-debug problems if you use larger keys:
https://github.com/awslabs/s2n/blob/4f7d3e65ac3b10518a5718b8ac592969bae7616c/crypto/s2n_rsa.c#L181
I ran into this problem on OS X and iOS (Apple also has a hard-limit of 4096bit for RSA keys) because I'm using larger (=8192bit) keys. It would be great if such things are made configurable from a central point or even made dynamic (with configurable absolute maximum to prevent DoS).
If I find some time, I may search and replace such things myself.
s2n_realloc() does b->data = realloc(b->data, size)
and if b->data is then NULL it returns an error. By then, the reference to the still allocated, still valid, original memory at the original b->data has been lost and the memory leaked. b->data is now NULL yet b->size isn't zero. (This is a very common pattern of error when using realloc(3).) The return value of realloc() needs storing in a temporary and the library needs to decide if b is still intended to be valid on realloc() failure. (I would expect so.)
In https://github.com/awslabs/s2n/blame/master/docs/USAGE-GUIDE.md#L83
The URL does not exist. The path to the tarball on line 83 and 84 should instead be: https://www.openssl.org/source/openssl-1.0.2-latest.tar.gz
There is no real need for RSA/ECDSA keys to reside in the same process as the user-application, or for that matter for the ephemeral keys used to encrypt data. TLS permits at least three process model;
While good for security, this kind of model might be tough to make performant; especially to privsep the 2nd process. Can we use vmsplice() to help here? are Unix pipes the way to go? or some kind of lockless ring structure using shared memory? is the additional complexity worth it?
Callers should be able to express protocol-level preferences and have these protocols negotiated.
Tentative API:
s2n_config_set_protocol_preferences(config, "SPDY > HTTP", &err);
char *protocol = s2n_connection_get_protocol(conn, &err);
Building commit 748ed6 of s2n on Ubuntu 14.04 x86_64 with gcc 4.8.4 and the (default) bfd linker.
I've tried libressl versions 2.2.0, 2.1.7, 2.0.5 and all produce similar errors when I try to make s2n:
gcc -shared -lc -lpthread -lrt -o libs2n.so ../utils/s2n_blob.o ../utils/s2n_mem.o ../utils/s2n_random.o ../utils/s2n_safety.o ../utils/s2n_timer.o ../stuffer/s2n_stuffer_base64.o ../stuffer/s2n_stuffer_file.o ../stuffer/s2n_stuffer.o ../stuffer/s2n_stuffer_pem.o ../stuffer/s2n_stuffer_text.o ../tls/s2n_aead.o ../tls/s2n_alerts.o ../tls/s2n_cbc.o ../tls/s2n_cipher_suites.o ../tls/s2n_client_ccs.o ../tls/s2n_client_extensions.o ../tls/s2n_client_finished.o ../tls/s2n_client_hello.o ../tls/s2n_client_key_exchange.o ../tls/s2n_config.o ../tls/s2n_connection.o ../tls/s2n_handshake_io.o ../tls/s2n_handshake.o ../tls/s2n_ocsp_stapling.o ../tls/s2n_prf.o ../tls/s2n_record_read.o ../tls/s2n_record_write.o ../tls/s2n_recv.o ../tls/s2n_send.o ../tls/s2n_server_ccs.o ../tls/s2n_server_cert.o ../tls/s2n_server_done.o ../tls/s2n_server_extensions.o ../tls/s2n_server_finished.o ../tls/s2n_server_hello.o ../tls/s2n_server_key_exchange.o ../tls/s2n_tls.o ../crypto/s2n_aead_cipher_aes_gcm.o ../crypto/s2n_cbc_cipher_3des.o ../crypto/s2n_cbc_cipher_aes.o ../crypto/s2n_dhe.o ../crypto/s2n_drbg.o ../crypto/s2n_ecc.o ../crypto/s2n_hash.o ../crypto/s2n_hmac.o ../crypto/s2n_rsa.o ../crypto/s2n_sequence.o ../crypto/s2n_stream_cipher_null.o ../crypto/s2n_stream_cipher_rc4.o ../error/s2n_errno.o ../libcrypto-root/lib/libcrypto.a
/usr/bin/ld: ../libcrypto-root/lib/libcrypto.a(libcrypto_la-cryptlib.o): relocation R_X86_64_32 against `.rodata.str1.8' can not be used when making a shared object; recompile with -fPIC
../libcrypto-root/lib/libcrypto.a: error adding symbols: Bad value
collect2: error: ld returned 1 exit status
make[1]: *** [libs2n.so] Error 1
make[1]: Leaving directory `/home/mcarpenter/s2n/lib'
make: *** [libs] Error 2
Following the hint it's enough to do export CFLAGS=-fPIC
before building libressl (2.2.0) and then s2n. (Even then the s2n build doesn't quite complete since tests fail... but one step at a time).
Is this just a doc error ("please set CFLAGS
")? Or is there something more fundamentally wrong?
On a clean Ubuntu 14.04, with a uptodate git version of s2n, the commands
apt-get update
apt-get upgrade
apt-get install git build-essential openssl libssl-dev
git clone https://github.com/awslabs/s2n.git
cd s2n/
make clean
make
result in the errors below. Tips how to solve this are welcome.
<snip>
make -C bin
make[1]: Entering directory `/git/s2n/bin'
cc -pedantic -Wall -Werror -Wimplicit -Wunused -Wcomment -Wchar-subscripts -Wuninitialized -Wshadow -Wcast-qual -Wcast-align -Wwrite-strings -Wstack-protector -fPIC -std=c99 -D_POSIX_C_SOURCE=200112L -fstack-protector-all -O2 -I../libcrypto-root/include/ -I../api/ -I../ -Wno-deprecated-declarations -Wno-unknown-pragmas -Wformat-security -D_FORTIFY_SOURCE=2 s2nc.c echo.c -o s2nc -L../lib/ -ls2n -ldl -lrt -lpthread
../lib//libs2n.so: undefined reference to `EVP_DecryptFinal_ex'
../lib//libs2n.so: undefined reference to `SHA224_Update'
../lib//libs2n.so: undefined reference to `ENGINE_free'
../lib//libs2n.so: undefined reference to `EC_KEY_set_public_key'
../lib//libs2n.so: undefined reference to `DHparams_dup'
../lib//libs2n.so: undefined reference to `SHA384_Init'
../lib//libs2n.so: undefined reference to `RSA_public_encrypt'
../lib//libs2n.so: undefined reference to `ENGINE_set_default'
../lib//libs2n.so: undefined reference to `EVP_aes_128_gcm'
../lib//libs2n.so: undefined reference to `ENGINE_set_init_function'
../lib//libs2n.so: undefined reference to `MD5_Final'
../lib//libs2n.so: undefined reference to `ENGINE_init'
../lib//libs2n.so: undefined reference to `RSA_size'
../lib//libs2n.so: undefined reference to `EVP_aes_256_cbc'
../lib//libs2n.so: undefined reference to `ENGINE_set_flags'
../lib//libs2n.so: undefined reference to `EC_KEY_get0_public_key'
../lib//libs2n.so: undefined reference to `ENGINE_add'
../lib//libs2n.so: undefined reference to `BN_num_bits'
../lib//libs2n.so: undefined reference to `RC4'
../lib//libs2n.so: undefined reference to `BN_bin2bn'
../lib//libs2n.so: undefined reference to `RSA_free'
../lib//libs2n.so: undefined reference to `EVP_PKEY_free'
../lib//libs2n.so: undefined reference to `EC_POINT_oct2point'
../lib//libs2n.so: undefined reference to `SHA384_Update'
../lib//libs2n.so: undefined reference to `ENGINE_new'
../lib//libs2n.so: undefined reference to `SHA224_Init'
../lib//libs2n.so: undefined reference to `SHA256_Init'
../lib//libs2n.so: undefined reference to `SHA512_Update'
../lib//libs2n.so: undefined reference to `d2i_RSAPrivateKey'
../lib//libs2n.so: undefined reference to `EVP_CIPHER_CTX_init'
../lib//libs2n.so: undefined reference to `DH_new'
../lib//libs2n.so: undefined reference to `BN_free'
../lib//libs2n.so: undefined reference to `EC_KEY_generate_key'
../lib//libs2n.so: undefined reference to `EVP_EncryptUpdate'
../lib//libs2n.so: undefined reference to `X509_get_pubkey'
../lib//libs2n.so: undefined reference to `DH_free'
../lib//libs2n.so: undefined reference to `EC_KEY_get0_group'
../lib//libs2n.so: undefined reference to `EVP_aes_128_ecb'
../lib//libs2n.so: undefined reference to `EVP_CIPHER_CTX_set_padding'
../lib//libs2n.so: undefined reference to `EVP_PKEY_get1_RSA'
../lib//libs2n.so: undefined reference to `SHA1_Update'
../lib//libs2n.so: undefined reference to `RSA_verify'
../lib//libs2n.so: undefined reference to `ENGINE_set_name'
../lib//libs2n.so: undefined reference to `EVP_DecryptInit_ex'
../lib//libs2n.so: undefined reference to `RC4_set_key'
../lib//libs2n.so: undefined reference to `EVP_EncryptFinal_ex'
../lib//libs2n.so: undefined reference to `d2i_DHparams'
../lib//libs2n.so: undefined reference to `DH_compute_key'
../lib//libs2n.so: undefined reference to `DH_generate_key'
../lib//libs2n.so: undefined reference to `BN_bn2bin'
../lib//libs2n.so: undefined reference to `SHA512_Final'
../lib//libs2n.so: undefined reference to `EVP_EncryptInit_ex'
../lib//libs2n.so: undefined reference to `EC_POINT_point2oct'
../lib//libs2n.so: undefined reference to `EVP_CIPHER_CTX_ctrl'
../lib//libs2n.so: undefined reference to `ENGINE_set_id'
../lib//libs2n.so: undefined reference to `EVP_aes_256_gcm'
../lib//libs2n.so: undefined reference to `DH_size'
../lib//libs2n.so: undefined reference to `EVP_aes_128_cbc'
../lib//libs2n.so: undefined reference to `SHA256_Final'
../lib//libs2n.so: undefined reference to `SHA1_Init'
../lib//libs2n.so: undefined reference to `SHA224_Final'
../lib//libs2n.so: undefined reference to `EC_KEY_free'
../lib//libs2n.so: undefined reference to `X509_free'
../lib//libs2n.so: undefined reference to `EVP_des_ede3_cbc'
../lib//libs2n.so: undefined reference to `d2i_X509'
../lib//libs2n.so: undefined reference to `SHA256_Update'
../lib//libs2n.so: undefined reference to `RSA_sign'
../lib//libs2n.so: undefined reference to `EC_GROUP_get_degree'
../lib//libs2n.so: undefined reference to `EVP_DecryptUpdate'
../lib//libs2n.so: undefined reference to `MD5_Init'
../lib//libs2n.so: undefined reference to `ENGINE_set_RAND'
../lib//libs2n.so: undefined reference to `MD5_Update'
../lib//libs2n.so: undefined reference to `EC_POINT_free'
../lib//libs2n.so: undefined reference to `EC_POINT_new'
../lib//libs2n.so: undefined reference to `RSA_private_decrypt'
../lib//libs2n.so: undefined reference to `ECDH_compute_key'
../lib//libs2n.so: undefined reference to `SHA1_Final'
../lib//libs2n.so: undefined reference to `EC_KEY_new_by_curve_name'
../lib//libs2n.so: undefined reference to `ENGINE_by_id'
../lib//libs2n.so: undefined reference to `EVP_CIPHER_CTX_cleanup'
../lib//libs2n.so: undefined reference to `SHA512_Init'
collect2: error: ld returned 1 exit status
make[1]: *** [s2nc] Error 1
make[1]: Leaving directory `/git/s2n/bin'
make: *** [bin] Error 2
The file /usr/include/openssl/evp.h
is there:
# grep -irn EVP_DecryptFinal_ex *
crypto/s2n_aead_cipher_aes_gcm.c:103: if (EVP_DecryptFinal_ex(&key->native_format.evp_cipher_ctx, out_data, &out_len) != 1) {
# grep -irn EVP_DecryptFinal_ex /usr/include/
/usr/include/openssl/evp.h:596:int EVP_DecryptFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *outm, int *outl);
/usr/include/openssl/evp.h:1274:#define EVP_F_EVP_DECRYPTFINAL_EX 101
The build was previously working for me on OS X, but now is failing with the following error:
s2n_aead_cipher_aes_gcm.c:61:65: error: use of undeclared identifier 'EVP_CTRL_GCM_GET_TAG'
if (EVP_CIPHER_CTX_ctrl(&key->native_format.evp_cipher_ctx, EVP_CTRL_GCM_GET_TAG, S2N_TLS_GCM_TAG_LEN, tag_data) != 1) {
^
s2n_aead_cipher_aes_gcm.c:87:65: error: use of undeclared identifier 'EVP_CTRL_GCM_SET_TAG'
if (EVP_CIPHER_CTX_ctrl(&key->native_format.evp_cipher_ctx, EVP_CTRL_GCM_SET_TAG, S2N_TLS_GCM_TAG_LEN, tag_data) == 0) {
^
s2n_aead_cipher_aes_gcm.c:115:60: error: implicit declaration of function 'EVP_aes_128_gcm' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
EVP_EncryptInit_ex(&key->native_format.evp_cipher_ctx, EVP_aes_128_gcm(), NULL, NULL, NULL);
^
s2n_aead_cipher_aes_gcm.c:115:60: note: did you mean 'EVP_aes_128_ecb'?
/usr/include/openssl/evp.h:758:19: note: 'EVP_aes_128_ecb' declared here
const EVP_CIPHER EVP_aes_128_ecb(void) DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER;
^
s2n_aead_cipher_aes_gcm.c:115:60: error: incompatible integer to pointer conversion passing 'int' to parameter of type 'const EVP_CIPHER *' (aka 'const struct evp_cipher_st *') [-Werror,-Wint-conversion]
EVP_EncryptInit_ex(&key->native_format.evp_cipher_ctx, EVP_aes_128_gcm(), NULL, NULL, NULL);
^~~~~~~~~~~~~~~~~
/usr/include/openssl/evp.h:580:62: note: passing argument to parameter 'cipher' here
int EVP_EncryptInit_ex(EVP_CIPHER_CTX *ctx,const EVP_CIPHER *cipher, ENGINE *impl,
^
s2n_aead_cipher_aes_gcm.c:116:61: error: use of undeclared identifier 'EVP_CTRL_GCM_SET_IVLEN'
EVP_CIPHER_CTX_ctrl(&key->native_format.evp_cipher_ctx, EVP_CTRL_GCM_SET_IVLEN, S2N_TLS_GCM_IV_LEN, NULL);
^
s2n_aead_cipher_aes_gcm.c:127:60: error: implicit declaration of function 'EVP_aes_256_gcm' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
EVP_EncryptInit_ex(&key->native_format.evp_cipher_ctx, EVP_aes_256_gcm(), NULL, NULL, NULL);
^
s2n_aead_cipher_aes_gcm.c:127:60: note: did you mean 'EVP_aes_256_ecb'?
/usr/include/openssl/evp.h:778:19: note: 'EVP_aes_256_ecb' declared here
const EVP_CIPHER *EVP_aes_256_ecb(void) DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER;
^
s2n_aead_cipher_aes_gcm.c:127:60: error: incompatible integer to pointer conversion passing 'int' to parameter of type 'const EVP_CIPHER *' (aka 'const struct evp_cipher_st *') [-Werror,-Wint-conversion]
EVP_EncryptInit_ex(&key->native_format.evp_cipher_ctx, EVP_aes_256_gcm(), NULL, NULL, NULL);
^~~~~~~~~~~~~~~~~
/usr/include/openssl/evp.h:580:62: note: passing argument to parameter 'cipher' here
int EVP_EncryptInit_ex(EVP_CIPHER_CTX *ctx,const EVP_CIPHER *cipher, ENGINE *impl,
^
s2n_aead_cipher_aes_gcm.c:128:61: error: use of undeclared identifier 'EVP_CTRL_GCM_SET_IVLEN'
EVP_CIPHER_CTX_ctrl(&key->native_format.evp_cipher_ctx, EVP_CTRL_GCM_SET_IVLEN, S2N_TLS_GCM_IV_LEN, NULL);
^
s2n_aead_cipher_aes_gcm.c:139:60: error: incompatible integer to pointer conversion passing 'int' to parameter of type 'const EVP_CIPHER *' (aka 'const struct evp_cipher_st *') [-Werror,-Wint-conversion]
EVP_DecryptInit_ex(&key->native_format.evp_cipher_ctx, EVP_aes_128_gcm(), NULL, NULL, NULL);
^~~~~~~~~~~~~~~~~
/usr/include/openssl/evp.h:589:62: note: passing argument to parameter 'cipher' here
int EVP_DecryptInit_ex(EVP_CIPHER_CTX *ctx,const EVP_CIPHER *cipher, ENGINE *impl,
^
s2n_aead_cipher_aes_gcm.c:140:61: error: use of undeclared identifier 'EVP_CTRL_GCM_SET_IVLEN'
EVP_CIPHER_CTX_ctrl(&key->native_format.evp_cipher_ctx, EVP_CTRL_GCM_SET_IVLEN, S2N_TLS_GCM_IV_LEN, NULL);
^
s2n_aead_cipher_aes_gcm.c:151:60: error: incompatible integer to pointer conversion passing 'int' to parameter of type 'const EVP_CIPHER *' (aka 'const struct evp_cipher_st *') [-Werror,-Wint-conversion]
EVP_DecryptInit_ex(&key->native_format.evp_cipher_ctx, EVP_aes_256_gcm(), NULL, NULL, NULL);
^~~~~~~~~~~~~~~~~
/usr/include/openssl/evp.h:589:62: note: passing argument to parameter 'cipher' here
int EVP_DecryptInit_ex(EVP_CIPHER_CTX *ctx,const EVP_CIPHER *cipher, ENGINE *impl,
^
s2n_aead_cipher_aes_gcm.c:152:61: error: use of undeclared identifier 'EVP_CTRL_GCM_SET_IVLEN'
EVP_CIPHER_CTX_ctrl(&key->native_format.evp_cipher_ctx, EVP_CTRL_GCM_SET_IVLEN, S2N_TLS_GCM_IV_LEN, NULL);
^
12 errors generated.
make[1]: ** [s2n_aead_cipher_aes_gcm.o] Error 1
make: *** [libs] Error 2
Attempting to build on a Debian stable armhf system. I was building against libssl1.0.2c
cc -pedantic -Wall -Werror -Wimplicit -Wunused -Wcomment -Wchar-subscripts -Wuninitialized -Wshadow -Wcast-qual -Wcast-align -Wwrite-strings -Wstack-protector -fPIC -std=c99 -D_POSIX_C_SOURCE=200112L -fstack-protector-all -O2 -I../libcrypto-root/include/ -I../api/ -I../ -Wno-deprecated-declarations -Wno-unknown-pragmas -Wformat-security -D_FORTIFY_SOURCE=2 s2nc.c echo.c -o s2nc -L../lib/ -ls2n -ldl -lrt -lpthread
/usr/bin/ld: s2nc: hidden symbol `pthread_atfork' in /usr/lib/arm-linux-gnueabihf/libpthread_nonshared.a(pthread_atfork.oS) is referenced by DSO
/usr/bin/ld: final link failed: Bad value
gcc (Debian 4.9.2-10) 4.9.2
4:4.9.2-2
GNU ld (GNU Binutils for Debian) 2.25
2.25-5
Right now s2n uses /dev/urandom for all entropy, per the example of the excellent NaCL library, best summarized by Thomas Ptacek: http://sockpuppet.org/blog/2014/02/25/safely-generate-random-numbers/ .
The problem with using /dev/urandom though is that it is slow; at present it is the main (and really only) performance bottleneck in s2n. Reading from /dev/urandom involves kernel level locks and context switching. A quick benchmark shows that it's about a hundred times slower than using an in-process PRNG.
A modern PRNG should be safe to generate unpredictable and randomly distributed data once it has been seeded with about 256 bits of meaningful entropy, an in-process PRNG can be secure in that sense.
Unfortunately PRNGs are also inherently stateful and it is very difficult to guarantee that the internal state won't be replicated between processes. C99 does offer strong guarantees around thread local storage and it's relatively easy to ensure that two threads are seeded independently, but so far I've found no ironclad way to ensure that a fork() , or worse ... syscall(SYS_fork...) won't result in two processes having identically seeded PRNGs. This is particularly bad with TLS, because randomly-distributed data can sometimes be public (explicit IVs) and sometimes be very sensitive and private (PFS key generation).
One initially promising solution is to guard access to the PRNG with a getpid() call, and to detect changes in PID and reseed when needed. Unfortunately this also turns out not to be reliable: http://yarchive.net/comp/linux/getpid_caching.html libc can cache the PID value and get it wrong in some circumstances.
Since it's feasible that s2n will be used inside language runtimes (e.g. the JVM, Ruby, Python ..), it's not unrealistic to expect the calling application to call fork(), vfork() or even syscall(SYS_fork) , it's best to protect against this in a robust way.
If getentropy()/getrandom() have better locking/performance semantics, using them may help, but these are not widely available. Another solution maybe to use the RDRAND instruction directly where available, but this comes with its own challenges. See also djb's write up at: http://blog.cr.yp.to/20140205-entropy.html.
We need an example server/client that uses async/non-blocking I/O patterns. Perhaps a small stunnel-like proxy?
Mikko from codenomicon reported the following build error:
In file included from ../../tls/s2n_config.h:18:0,
from ../../tls/s2n_crypto.h:18,
from ../../tls/s2n_handshake.h:21,
from ../../tls/s2n_connection.h:23,
from s2n_print_connection.c:18:
../../crypto/s2n_rsa.h:18:25: fatal error: openssl/rsa.h: No such file or directory #include <openssl/rsa.h>
It looks like the problem is that our testlib/Makefile does not include the right libcrypto-build in its path. I suspect that the following patch fixes it:
diff --git a/tests/testlib/Makefile b/tests/testlib/Makefile
index beaeffa..6c19478 100644
--- a/tests/testlib/Makefile
+++ b/tests/testlib/Makefile
@@ -20,7 +20,7 @@ all: libtests2n.so libtests2n.dylib
include ../../s2n.mk
-CFLAGS += -I../../ -I../../api/
+CFLAGS += -I../../ -I../../api/ -I../../libcrypto-root/include/
LDFLAGS += -L../../lib/ -lcrypto -lpthread -ls2n
libtests2n.so: ${OBJS}:
The s2n.h header does not include the right namespace magic to be usable from C++
s2n_init() opens /dev/urandom and overrides OpenSSL's entropy gathering routines, but there is no corresponding s2n_finalize() call to undo this operation.
At present s2n has a single fixed ordering for cipher suites. These defaults should suit most users, but some flexibility is probably necessary.
Tentative proposal for an API:
s2n_config_set_cipher_preferences(config, "AES128 > 3DES > RC4", &err);
s2n_config_set_exchange_preferences(config, "DHE > RSA", &err);
steps to repro:
Mac OSX 10.10.3
git clone https://github.com/awslabs/s2n.git
cd s2n
make
error:
s2n_random.c:213:29: error: use of undeclared identifier
'ENGINE_FLAGS_NO_REGISTER_ALL'
ENGINE_set_flags(e, ENGINE_FLAGS_NO_REGISTER_ALL) != 1 ||
The copyright notices contain the phrase "All rights reserved."
I believe this to be an error. The sentence should be removed.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.