Git Product home page Git Product logo

rustls's Introduction

Rustls is a modern TLS library written in Rust.

Status

Rustls is used in production at many organizations and projects. We aim to maintain reasonable API surface stability but the API may evolve as we make changes to accomodate new features or performance improvements.

We have a roadmap for our future plans. We also have benchmarks to prevent performance regressions and to let you evaluate rustls on your target hardware.

If you'd like to help out, please see CONTRIBUTING.md.

Build Status Coverage Status (codecov.io) Documentation Chat

Changelog

The detailed list of changes in each release can be found at https://github.com/rustls/rustls/releases.

Documentation

https://docs.rs/rustls/

Approach

Rustls is a TLS library that aims to provide a good level of cryptographic security, requires no configuration to achieve that security, and provides no unsafe features or obsolete cryptography by default.

Rustls implements TLS1.2 and TLS1.3 for both clients and servers. See the full list of protocol features.

Platform support

While Rustls itself is platform independent, by default it uses aws-lc-rs for implementing the cryptography in TLS. See the aws-lc-rs FAQ for more details of the platform/architecture support constraints in aws-lc-rs.

ring is also available via the ring crate feature: see the supported ring target platforms.

By providing a custom instance of the crypto::CryptoProvider struct, you can replace all cryptography dependencies of rustls. This is a route to being portable to a wider set of architectures and environments, or compliance requirements. See the crypto::CryptoProvider documentation for more details.

Specifying default-features = false when depending on rustls will remove the dependency on aws-lc-rs.

Rustls requires Rust 1.63 or later.

Cryptography providers

Since Rustls 0.22 it has been possible to choose the provider of the cryptographic primitives that Rustls uses. This may be appealing if you have specific platform, compliance or feature requirements that aren't met by the default provider, aws-lc-rs.

Users that wish to customize the provider in use can do so when constructing ClientConfig and ServerConfig instances using the with_crypto_provider method on the respective config builder types. See the crypto::CryptoProvider documentation for more details.

Built-in providers

Rustls ships with two built-in providers controlled with associated feature flags:

  • aws-lc-rs - enabled by default, available with the aws_lc_rs feature flag enabled.
  • ring - available with the ring feature flag enabled.

See the documentation for crypto::CryptoProvider for details on how providers are selected.

Third-party providers

The community has also started developing third-party providers for Rustls:

Custom provider

We also provide a simple example of writing your own provider in the custom-provider example. This example implements a minimal provider using parts of the RustCrypto ecosystem.

See the Making a custom CryptoProvider section of the documentation for more information on this topic.

Example code

Our examples directory contains demos that show how to handle I/O using the stream::Stream helper, as well as more complex asynchronous I/O using mio. If you're already using Tokio for an async runtime you may prefer to use tokio-rustls instead of interacting with rustls directly.

The mio based examples are the most complete, and discussed below. Users new to Rustls may prefer to look at the simple client/server examples before diving in to the more complex MIO examples.

Client example program

The MIO client example program is named tlsclient-mio. The interface looks like:

Connects to the TLS server at hostname:PORT.  The default PORT
is 443.  By default, this reads a request from stdin (to EOF)
before making the connection.  --http replaces this with a
basic HTTP GET request for /.

If --cafile is not supplied, a built-in set of CA certificates
are used from the webpki-roots crate.

Usage:
  tlsclient-mio [options] [--suite SUITE ...] [--proto PROTO ...] [--protover PROTOVER ...] <hostname>
  tlsclient-mio (--version | -v)
  tlsclient-mio (--help | -h)

Options:
    -p, --port PORT     Connect to PORT [default: 443].
    --http              Send a basic HTTP GET request for /.
    --cafile CAFILE     Read root certificates from CAFILE.
    --auth-key KEY      Read client authentication key from KEY.
    --auth-certs CERTS  Read client authentication certificates from CERTS.
                        CERTS must match up with KEY.
    --protover VERSION  Disable default TLS version list, and use
                        VERSION instead.  May be used multiple times.
    --suite SUITE       Disable default cipher suite list, and use
                        SUITE instead.  May be used multiple times.
    --proto PROTOCOL    Send ALPN extension containing PROTOCOL.
                        May be used multiple times to offer several protocols.
    --no-tickets        Disable session ticket support.
    --no-sni            Disable server name indication support.
    --insecure          Disable certificate verification.
    --verbose           Emit log output.
    --max-frag-size M   Limit outgoing messages to M bytes.
    --version, -v       Show tool version.
    --help, -h          Show this screen.

Some sample runs:

$ cargo run --bin tlsclient-mio -- --http mozilla-modern.badssl.com
HTTP/1.1 200 OK
Server: nginx/1.6.2 (Ubuntu)
Date: Wed, 01 Jun 2016 18:44:00 GMT
Content-Type: text/html
Content-Length: 644
(...)

or

$ cargo run --bin tlsclient-mio -- --http expired.badssl.com
TLS error: InvalidCertificate(Expired)
Connection closed

Server example program

The MIO server example program is named tlsserver-mio. The interface looks like:

Runs a TLS server on :PORT.  The default PORT is 443.

`echo' mode means the server echoes received data on each connection.

`http' mode means the server blindly sends a HTTP response on each
connection.

`forward' means the server forwards plaintext to a connection made to
localhost:fport.

`--certs' names the full certificate chain, `--key' provides the
RSA private key.

Usage:
  tlsserver-mio --certs CERTFILE --key KEYFILE [--suite SUITE ...] [--proto PROTO ...] [--protover PROTOVER ...] [options] echo
  tlsserver-mio --certs CERTFILE --key KEYFILE [--suite SUITE ...] [--proto PROTO ...] [--protover PROTOVER ...] [options] http
  tlsserver-mio --certs CERTFILE --key KEYFILE [--suite SUITE ...] [--proto PROTO ...] [--protover PROTOVER ...] [options] forward <fport>
  tlsserver-mio (--version | -v)
  tlsserver-mio (--help | -h)

Options:
    -p, --port PORT     Listen on PORT [default: 443].
    --certs CERTFILE    Read server certificates from CERTFILE.
                        This should contain PEM-format certificates
                        in the right order (the first certificate should
                        certify KEYFILE, the last should be a root CA).
    --key KEYFILE       Read private key from KEYFILE.  This should be a RSA
                        private key or PKCS8-encoded private key, in PEM format.
    --ocsp OCSPFILE     Read DER-encoded OCSP response from OCSPFILE and staple
                        to certificate.  Optional.
    --auth CERTFILE     Enable client authentication, and accept certificates
                        signed by those roots provided in CERTFILE.
    --crl CRLFILE ...   Perform client certificate revocation checking using the DER-encoded
                        CRLFILE. May be used multiple times.
    --require-auth      Send a fatal alert if the client does not complete client
                        authentication.
    --resumption        Support session resumption.
    --tickets           Support tickets.
    --protover VERSION  Disable default TLS version list, and use
                        VERSION instead.  May be used multiple times.
    --suite SUITE       Disable default cipher suite list, and use
                        SUITE instead.  May be used multiple times.
    --proto PROTOCOL    Negotiate PROTOCOL using ALPN.
                        May be used multiple times.
    --verbose           Emit log output.
    --version, -v       Show tool version.
    --help, -h          Show this screen.

Here's a sample run; we start a TLS echo server, then connect to it with openssl and tlsclient-mio:

$ cargo run --bin tlsserver-mio -- --certs test-ca/rsa/end.fullchain --key test-ca/rsa/end.rsa -p 8443 echo &
$ echo hello world | openssl s_client -ign_eof -quiet -connect localhost:8443
depth=2 CN = ponytown RSA CA
verify error:num=19:self signed certificate in certificate chain
hello world
^C
$ echo hello world | cargo run --bin tlsclient-mio -- --cafile test-ca/rsa/ca.cert -p 8443 localhost
hello world
^C

License

Rustls is distributed under the following three licenses:

  • Apache License version 2.0.
  • MIT license.
  • ISC license.

These are included as LICENSE-APACHE, LICENSE-MIT and LICENSE-ISC respectively. You may use this software under the terms of any of these licenses, at your option.

Project Membership

  • Joe Birr-Pixton (@ctz, Project Founder - full-time funded by Prossimo)
  • Dirkjan Ochtman (@djc, Co-maintainer)
  • Daniel McCarney (@cpu, Co-maintainer - full-time funded by Prossimo)
  • Josh Aas (@bdaehlie, Project Management)

Code of conduct

This project adopts the Rust Code of Conduct. Please email [email protected] to report any instance of misconduct, or if you have any comments or questions on the Code of Conduct.

rustls's People

Contributors

alex avatar aochagavia avatar bdaehlie avatar briansmith avatar complexspaces avatar cpu avatar ctz avatar davidv1992 avatar dependabot-preview[bot] avatar dependabot[bot] avatar divergentdave avatar djc avatar erickt avatar francisrussell avatar frewsxcv avatar japaric avatar jbr avatar jeromegn avatar jsha avatar jsoref avatar keruspe avatar potatosalad avatar pvdrz avatar ralith avatar sayrer avatar stepancheg avatar taowyoo avatar thomwiggers avatar wonshtrum avatar zkonge avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

rustls's Issues

Fails tests on OS X

It doesn't know how to find the CA certificate store on OS X, looks like:

---- online::no_cbc stdout ----
    We expected to find 'TLS error: AlertReceived(HandshakeFailure)' in the following output:
Output { status: ExitStatus(ExitStatus(25856)), stdout: "", stderr: "thread \'main\' panicked at \'cannot open CA file \'/etc/ssl/certs/ca-certificates.crt\': Error { repr: Os { code: 2, message: \"No such file or directory\" } }\nConsider using the --cafile option to provide a valid CA file.\', examples/tlsclient.rs:408\nnote: Run with `RUST_BACKTRACE=1` for a backtrace.\n" }
thread 'online::no_cbc' panicked at 'Test failed', tests/common/mod.rs:231
note: Run with `RUST_BACKTRACE=1` for a backtrace.

couldn't compile

error: no matching package named `untrusted` found (required by `rustls`)
location searched: https://github.com/briansmith/untrusted
version required: ^0.1.0
versions found: 0.2.0

Add ability to configure server certificate resolvers

The ResolvesCert trait is currently private, so it's not possible to provide a custom certificate resolver, which would be useful for providing different certificates based on the domain name in a request with SNI. However this may also require stabilizing/exposing the additional types in the resolve() interface, like ServerNameRequest, SupportedSignatureAlgorithms, EllipticCurveList and ECPointFormatList.

Finish server-side resumption

This has some stuff in server.rs, but is not plumbed into the the protocol code.

Once that's done, there's a ton of additional tests in bogo which can be run.

Add types to pemfile

I believe you want to add struct Certificate(Vec<u8>) and struct SecretKey(Vec<u8>) to module pemfile, in order to make it clearer what these things are, and what arguments other functions are expecting (I believe this to be 0-cost in Rust, as they have the same memory representation as Vec<u8>. Correct me if I'm wrong).

Then pemfile::certs would return Vec<Certificate> and pemfile::rsa_private_key would return SecretKey.

Compilation fail using Rust nightly: The attribute `export_macro` is currently unknown to the compiler and may have meaning added to it in the future

Using Rust nightly: rustc 1.17.0-nightly (824c9ebbd 2017-03-12)

and compiling rustls as dependency to my crate I get:

error: The attribute `export_macro` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642)
 --> /Users/oherrala/.cargo/registry/src/github.com-1ecc6299db9ec823/rustls-0.5.7/src/msgs/macros.rs:3:1
  |
3 | #[export_macro]
  | ^^^^^^^^^^^^^^^
  |
  = help: add #![feature(custom_attribute)] to the crate attributes to enable

error: aborting due to previous error

Rust issue: rust-lang/rust#29642

Sever dying with assertion failure in RSA signature

Here's a complete backtrace from lldb:

Assertion failed: (p_bits <= (size_t)INT_MAX), function GFp_BN_mod_exp_mont_consttime, file crypto/bn/exponentiation.c, line 265.
Process 72563 stopped
* thread #2, stop reason = signal SIGABRT
    frame #0: 0x00007fffaaa98d42 libsystem_kernel.dylib`__pthread_kill + 10
libsystem_kernel.dylib`__pthread_kill:
->  0x7fffaaa98d42 <+10>: jae    0x7fffaaa98d4c            ; <+20>
    0x7fffaaa98d44 <+12>: movq   %rax, %rdi
    0x7fffaaa98d47 <+15>: jmp    0x7fffaaa91caf            ; cerror_nocancel
    0x7fffaaa98d4c <+20>: retq
(lldb) bt
error: need to add support for DW_TAG_base_type '()' encoded with DW_ATE = 0x7, bit_size = 0
* thread #2, stop reason = signal SIGABRT
  * frame #0: 0x00007fffaaa98d42 libsystem_kernel.dylib`__pthread_kill + 10
    frame #1: 0x00007fffaab865bf libsystem_pthread.dylib`pthread_kill + 90
    frame #2: 0x00007fffaa9fe420 libsystem_c.dylib`abort + 129
    frame #3: 0x00007fffaa9c5893 libsystem_c.dylib`__assert_rtn + 320
    frame #4: 0x00000001001ee55f ct-submitter`GFp_BN_mod_exp_mont_consttime(rr=0x0000700002b9e7f8, a_mont=0x0000700002b9e7f8, p=0x0000000102a59068, p_bits=4339372160, one_mont=0x0000000102a59040, n=0x0000000102a59058, n0=0x0000000102a59058) at exponentiation.c:265
    frame #5: 0x000000010078914e ct-submitter`ring::rsa::bigint::elem_exp_consttime<ring::rsa::signing::P>(base=Elem<ring::rsa::signing::P, ring::arithmetic::montgomery::R> @ 0x0000700002b9e798, exponent=0x0000000102a59068, oneR=0x0000000102a59080, m=0x0000000102a59040) at bigint.rs:533
    frame #6: 0x000000010077e004 ct-submitter`ring::rsa::signing::elem_exp_consttime<ring::rsa::signing::P,ring::rsa::N>(c=0x0000700002b9eb20, p=0x0000000102a59040) at signing.rs:413
    frame #7: 0x000000010078fdae ct-submitter`ring::rsa::signing::{{impl}}::sign::{{closure}}(c=Elem<ring::rsa::N, ring::arithmetic::montgomery::Unencoded> @ 0x0000700002b9eb08) at signing.rs:545
    frame #8: 0x000000010078bd21 ct-submitter`ring::rsa::blinding::{{impl}}::blind<closure>(self=0x0000700002b9fed0, x=Elem<ring::rsa::N, ring::arithmetic::montgomery::Unencoded> @ 0x0000700002b9f230, e=(__0 = 65537), n=0x0000000102a59010, oneRR_mod_n=0x0000000102a59168, rng=&SecureRandom @ 0x0000700002b9f268, f=closure @ 0x0000700002b9f278) at blinding.rs:72
    frame #9: 0x000000010077e82e ct-submitter`ring::rsa::signing::{{impl}}::sign(self=0x0000700002b9fec8, padding_alg=&RSAEncoding๏ฟฝ\x8d๏ฟฝN๏ฟฝ๏ฟฝ[\f\x14๏ฟฝZl๏ฟฝ\x89\x82T]\r\x86๏ฟฝ๏ฟฝ๏ฟฝ๏ฟฝ๏ฟฝ๏ฟฝ฿ธ๏ฟฝ๏ฟฝb\x8c\x03", length = 100), signature=(data_ptr = "", length = 256)) at signing.rs:542
    frame #10: 0x00000001002dec78 ct-submitter`rustls::sign::{{impl}}::sign(self=0x0000000102a37060, scheme=SignatureScheme @ 0x00๏ฟฝ\x8d๏ฟฝN๏ฟฝ๏ฟฝ[\f\x14๏ฟฝZl๏ฟฝ\x89\x82T]\r\x86๏ฟฝ๏ฟฝ๏ฟฝ๏ฟฝ๏ฟฝ๏ฟฝ฿ธ๏ฟฝ๏ฟฝb\x8c\x03", length = 100)) at sign.rs:72
    frame #11: 0x00000001002b05e6 ct-submitter`rustls::server_hs::emit_server_kx(sess=0x000000010420cc00, sigscheme=SignatureScheme @ 0x0000700002ba01a0, group=0x0000700002ba1ea0, signer=Arc<alloc::boxed::Box<Signer>> @ 0x0000700002ba01b0) at server_hs.rs:188
    frame #12: 0x00000001002bb9c7 ct-submitter`rustls::server_hs::handle_client_hello(sess=0x000000010420cc00, m=Message @ 0x0000700002ba10a8) at server_hs.rs:894
    frame #13: 0x00000001002d9e58 ct-submitter`rustls::server::{{impl}}::process_main_protocol(self=0x000000010420cc00, msg=Message @ 0x0000700002ba2478) at server.rs:445
    frame #14: 0x00000001002d9848 ct-submitter`rustls::server::{{impl}}::process_new_handshake_messages(self=0x000000010420cc00) at server.rs:426
    frame #15: 0x00000001002d94bb ct-submitter`rustls::server::{{impl}}::process_msg(self=0x000000010420cc00, msg=Message @ 0x0000700002ba2d50) at server.rs:411
    frame #16: 0x00000001002da2cf ct-submitter`rustls::server::{{impl}}::process_new_packets(self=0x000000010420cc00) at server.rs:461
    frame #17: 0x00000001002daa6c ct-submitter`rustls::server::{{impl}}::process_new_packets(self=0x000000010420cc00) at server.rs:529
    frame #18: 0x00000001001d0509 ct-submitter`hyper_rustls::{{impl}}::underlying_read(self=0x0000000104219020) at lib.rs:49
    frame #19: 0x00000001001d0be6 ct-submitter`hyper_rustls::{{impl}}::underlying_io(self=0x0000000104219020) at lib.rs:70
    frame #20: 0x00000001001d1315 ct-submitter`hyper_rustls::{{impl}}::read(self=0x0000000104219020, buf=(data_ptr = "", length = 4096)) at lib.rs:116
    frame #21: 0x00000001001d1b68 ct-submitter`hyper_rustls::{{impl}}::read(self=0x0000700002ba6040, buf=(data_ptr = "", length = 4096)) at lib.rs:158
    frame #22: 0x00000001006a5034 ct-submitter`std::io::impls::{{impl}}::read<NetworkStream>(self=0x0000700002ba6048, buf=(data_ptr = "", length = 4096)) at impls.rs:23
    frame #23: 0x00000001006cf242 ct-submitter`hyper::buffer::{{impl}}::read_into_buf<&mut NetworkStream>(self=0x0000700002ba6048) at buffer.rs:89
    frame #24: 0x00000001006ec5de ct-submitter`hyper::http::h1::parse<&mut NetworkStream,httparse::Request,(hyper::method::Method, hyper::uri::RequestUri)>(rdr=0x0000700002ba6048) at h1.rs:886
    frame #25: 0x00000001006ebb6c ct-submitter`hyper::http::h1::parse_request<&mut NetworkStream>(buf=0x0000700002ba6048) at h1.rs:868
    frame #26: 0x00000001006ef5d8 ct-submitter`hyper::server::request::{{impl}}::new(stream=0x0000700002ba6048, addr=SocketAddr @ 0x0000700002ba49f0) at request.rs:40
    frame #27: 0x00000001000158f3 ct-submitter`hyper::server::{{impl}}::keep_alive_loop<ct_submitter::HttpHandler,std::io::buffered::BufWriter<&mut hyper_rustls::WrappedStream>>(self=0x000000010400d010, rdr=0x0000700002ba6048, wrt=0x0000700002ba6080, addr=SocketAddr @ 0x0000700002ba5400) at mod.rs:310
    frame #28: 0x0000000100017090 ct-submitter`hyper::server::{{impl}}::handle_connection<ct_submitter::HttpHandler,hyper_rustls::WrappedStream>(self=0x000000010400d010, stream=0x0000700002ba62f8) at mod.rs:292
    frame #29: 0x000000010006caed ct-submitter`hyper::server::handle::{{closure}}<ct_submitter::HttpHandler,hyper::net::HttpsListener<hyper_rustls::TlsServer>>(stream=WrappedStream @ 0x0000700002ba62e8) at mod.rs:251
    frame #30: 0x000000010006d0ed ct-submitter`hyper::server::listener::spawn_with::{{closure}}<hyper::net::HttpsListener<hyper_rustls::TlsServer>,closure> at listener.rs:50
    frame #31: 0x000000010008eaaf ct-submitter`std::panic::{{impl}}::call_once<(),closure>(self=AssertUnwindSafe<closure> @ 0x0000700002ba6550, _args=<unavailable>) at panic.rs:296
    frame #32: 0x0000000100022fa7 ct-submitter`std::panicking::try::do_call<std::panic::AssertUnwindSafe<closure>,()>(data="\x02") at panicking.rs:454
    frame #33: 0x00000001007b6a7b ct-submitter`panic_unwind::__rust_maybe_catch_panic at lib.rs:98 [opt]
    frame #34: 0x0000000100022bf9 ct-submitter`std::panicking::try<(),std::panic::AssertUnwindSafe<closure>>(f=AssertUnwindSafe<closure> @ 0x0000700002ba68f8) at panicking.rs:433
    frame #35: 0x0000000100020c49 ct-submitter`std::panic::catch_unwind<std::panic::AssertUnwindSafe<closure>,()>(f=AssertUnwindSafe<closure> @ 0x0000700002ba6ae8) at panic.rs:361
    frame #36: 0x0000000100022860 ct-submitter`std::thread::{{impl}}::spawn::{{closure}}<closure,()> at mod.rs:360
    frame #37: 0x000000010005f01a ct-submitter`alloc::boxed::{{impl}}::call_box<(),closure>(self=0x000000010401a000, args=<unavailable>) at boxed.rs:640
    frame #38: 0x00000001007b2b85 ct-submitter`std::sys::imp::thread::{{impl}}::new::thread_start [inlined] alloc::boxed::{{impl}}::call_once<(),()> at boxed.rs:650 [opt]
    frame #39: 0x00000001007b2b7f ct-submitter`std::sys::imp::thread::{{impl}}::new::thread_start [inlined] std::sys_common::thread::start_thread at thread.rs:21 [opt]
    frame #40: 0x00000001007b2b70 ct-submitter`std::sys::imp::thread::{{impl}}::new::thread_start at thread.rs:84 [opt]
    frame #41: 0x00007fffaab839af libsystem_pthread.dylib`_pthread_body + 180
    frame #42: 0x00007fffaab838fb libsystem_pthread.dylib`_pthread_start + 286
    frame #43: 0x00007fffaab83101 libsystem_pthread.dylib`thread_start + 13

This happens when attempting to connect to my server with Chrome or OpenSSL 1.1's s_client.

Code for configuring the server is simple:

    let mut tls_config = rustls::ServerConfig::new();
    tls_config.client_auth_offer = true;
    tls_config.client_auth_mandatory = true;
    tls_config.set_single_cert(hyper_rustls::util::load_certs(certificate_path).unwrap(),
                               hyper_rustls::util::load_private_key(private_key_path).unwrap());
    let tls_server = hyper_rustls::TlsServer { cfg: Arc::new(tls_config) };

And the certificate I'm using is a simple self-signed one:

-----BEGIN CERTIFICATE-----
MIICrDCCAZSgAwIBAgIUHSiudvcAcsqTcMosJOz7QIGwco8wDQYJKoZIhvcNAQEL
BQAwADAeFw0xNzA1MDUyMzQ0MTdaFw0xNzA1MjAyMzQ0MTdaMAAwggEiMA0GCSqG
SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDS/RAS5CDRvPxSUeMU/9W/Rn2ZEmmo321f
Vo47MDXiDPSM3MJ1vErEJEMs43YRT/oOVIe4MLtIVhFuO6IOVphpOjcM2DiDXogm
bHQWy1j9xR/Gov62aHFfxEjVNxV872gOUfViViK8iBjkzmBvDYWBMf1ESAURvayX
F9qcsZ+LW21yK9C+om+Gzbkfd/RhnhJRkNzOEsYny3NYyfE+6uDBai4RBAHIF7Ns
abhimaUSti4HGzQj/XBnpM1c8LlEY57xCtHhZh+ewvOokVBpAy4i9akpANKON/xw
dwTY+LSXKoLrxuYqixAvAWNMKPQd2xQlqbO8F7LJzOngyJ5saFpxAgMBAAGjHjAc
MBoGA1UdEQQTMBGCCWxvY2FsaG9zdIcEfwAAATANBgkqhkiG9w0BAQsFAAOCAQEA
K4aQojid+m3fJP6Zu7Ha5Qzjev8PqasF/niKQQ8ca/RjHmT9yX+mOYF1UQSsxBe4
WfMO/qm+xxw+k0ALGoPqDOM2OhYMJY2zZnHDvgHja03xEppaEKZkuQP2u3lqV4Qz
/heWH1fEGKeSbjacroBiazEmdOZucyGUOmSLFqs4nWsM7zMIxHF+iRj+IgUYuWGh
KbmoLu1U22minloj6mpTEsnOZ27tZR+n4gUVz6vw2pqIHu/V1sUq9WhLfqyCqMC2
nPtU1h5K/gi4ABx6q6b5ALP3nX7dMLbIQ184htsFMTsc0wqzVS7Y9MnGbGplP3EV
6twY+S145wTZ8CvR3h/3hg==
-----END CERTIFICATE-----

If there's any additional debugging info I can provide, please let me know! I strongly suspect what's really happening here is bad configuration leading to rustls / ring being in a weird state; in which case an actionable version of this issue might be "fail earlier with a clear error message", but it's also possible there's a real bug here.

Client authentication

Hi. If I use this library for writing a client. Can I set client certificate in the API for third party servers to do client authentication ?

To be more specific, I'm trying to write client code using your library (Thanks ๐Ÿ˜„ ) . I'm able to authenticate server by providing the CA (root_store .add_pem_file(ca.crt)). Can I also simultaneously add client certificate for 3rd party servers to authenticate this client?

(Didn't use tls much before. Plz let me know if my question itself doesn't make sense)

ALPN support is not useful

While we can negotiate the right protocol, we don't have an API tell the user what that protocol actually is.

Can't run example with system certificate

# RUST_BACKTRACE=1 /mnt/src/git/rustls/target/debug/examples/tlsserver --certs /etc/ssl/certs/ssl-cert-snakeoil.pem --key /etc/ssl/private/ssl-cert-snakeoil.key http
thread 'main' panicked at 'Invalid RSA private key: ()', ../src/libcore/result.rs:788
stack backtrace:
   1: 0x56943771 - std::sys::backtrace::tracing::imp::write::h482d45d91246faa2
   2: 0x56946bae - std::panicking::default_hook::_{{closure}}::h89158f66286b674e
   3: 0x56945879 - std::panicking::default_hook::h9e30d428ee3b0c43
   4: 0x56945f73 - std::panicking::rust_panic_with_hook::h2224f33fb7bf2f4c
   5: 0x56945dfd - std::panicking::begin_panic::hcb11a4dc6d779ae5
   6: 0x56945d0e - std::panicking::begin_panic_fmt::h310416c62f3935b3
   7: 0x56945c6e - rust_begin_unwind
   8: 0x5697ed04 - core::panicking::panic_fmt::hc5789f4e80194729
   9: 0x566603eb - core::result::unwrap_failed::h758c322be2590739
                at /buildslave/rust-buildbot/slave/nightly-dist-rustc-linux/build/obj/../src/libcore/result.rs:29
  10: 0x5664ffab - _<core..result..Result<T, E>>::expect::h5c4ab8a24731780f
                at /buildslave/rust-buildbot/slave/nightly-dist-rustc-linux/build/obj/../src/libcore/result.rs:750
  11: 0x566ca298 - rustls::server::AlwaysResolvesChain::new_rsa::h7532f7f3b684f42d
                at /mnt/src/git/rustls/src/server.rs:166
  12: 0x566cacfd - rustls::server::ServerConfig::set_single_cert::he44ef2078618689f
                at /mnt/src/git/rustls/src/server.rs:215
  13: 0x565fe1ae - tlsserver::make_config::h278ad6ef743ab7d9
                at /mnt/src/git/rustls/examples/tlsserver.rs:447
  14: 0x565fe95b - tlsserver::main::h418b28d9f946c5ad
                at /mnt/src/git/rustls/examples/tlsserver.rs:485
  15: 0x56945bb5 - std::panicking::try::do_call::h9d5ad283de22edbd
  16: 0x5694e307 - __rust_maybe_catch_panic
  17: 0x56945098 - std::rt::lang_start::h352a66f5026f54bd
  18: 0x5660383a - main
  19: 0xf7582722 - __libc_start_main
  20: 0x565bdbb0 - <unknown>

Command line from README with pre-supplied certificate works although.

ssl-cert-snakeoil.key also begins with -----BEGIN RSA PRIVATE KEY----- like test-ca/rsa/end.rsa. I suppose the error message should tell what is exactly wrong.

socat openssl-listen:8443,cert=/etc/ssl/certs/ssl-cert-snakeoil.pem,verify=0,key=/etc/ssl/private/ssl-cert-snakeoil.key - does work.

Malformed Server Hello / BadDER

Hi, was trying to use rustls (tokio-rustls). However, I can not make the handshake work.
I generated a CA key/cert and a server key/cert using OpenSSL. To verify the problem I used the tlsclient and tlsserver example. Both the client and the server start correctly (i.e. read the certificate and key files), however, the client exits with a WebPKIError(BadDER) error and Wireshark shows an malformed Server Hello packet (for example, the version field is 0x00007f12).

I guess there might be a problem with the generated certificates/keys, I can attach them if you like. However, I would expect to get a error message when the file is read and not invalid TLS records.

Determine when a handshake is finished?

Hello! In the ongoing quest to add rustls as a backend to tokio-tls, I've got one other question. Right now the bindings for other TLS libraries (openssl, secure transport, schannel) support the concept of a "mid handshake tls stream" where there's explicit knowledge that a stream is still in part of the tls handshake.

Would it be possible expose this, perhaps on the Session trait? This is used with futures right now in that when you perform a handshake it returns a future of an I/O object that represents when the handshake has successfully completed. Additionally, if the handshake fails, you could perhaps avoid allocating resources you'd only want if you were about to communicate.

Although I guess the other question here is if there's already a way to do this? If so, please feel free to close!

Support PKCS#8 key files

It seems that if a .key file has a PKCS#8 key including the key type it can't be parsed by pemfile::rsa_private_keys. I discovered this by running the tlsserver example with such a key and getting an assertion error about not finding any keys.

DTLS support

Do you plan on supporting DTLS (TLS over UDP)?

Fails to build with newest nightly (2017-03-15)

error: The attribute `export_macro` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642)
 --> ~/.cargo/registry/src/github.com-1ecc6299db9ec823/rustls-0.5.7/src/msgs/macros.rs:3:1
  |
3 | #[export_macro]
  | ^^^^^^^^^^^^^^^
  |
  = help: add #![feature(custom_attribute)] to the crate attributes to enable

Using rustls synchronously

When adapting hyper with blocking I/O to use rustls (for rustup's SSL stream adapter) I had to:

  1. Modify wants_read() to return false when there's unconsumed plaintext content in the buffer;
  2. Check wants_write() immediately after processing input packets, without which the initial protocol negotiation wouldn't finish.

With these modifications, rustup + hyper + rustls works fine in the limited testing I've put it through. What I'd like to know is a) whether the change in (1.) above is acceptable, or maybe some other function could be added to inquire about rustls' plaintext buffer status, and b) does (2.) hide some nasty surprise in the face of protocol errors and the like.

Please make `log` an optional dependency

In certain code paths, rustls uses the log crate's macros. In and of itself, that's fine. However, in a production environment , the logging is an overhead and isn't particularly useful (the TlsErrors, for example, being far more useful - thank you). More significantly, in many server environments, the log crate will either write to files or use syslog, both of which can be abused for a DoS attack (it's a classic - overwhelming application or OS logging, particularly on a gateway device, ssl-based jump in box, or the like).

Would you be open to the idea of making the log crate optional?

Share RootCertStore between ClientConfigs

Building RootCertStore is expensive. I expect to want a single instance for my entire app, but multiple ClientConfigs, and I don't want to rebuild the cert store. If it was Arcd then I could reuse it.

Provide socket-like API

E. g. similar to rust-native-tls:

let tcp_stream: TcpStream = ...;
let connector = ...; // which is called ClientConfig in rustls
let tls_stream: TlsStream<TcpStream> = connector.connect("github.com", tcp_stream);
// work with tls_stream as with `Read` and `Write`

panic on client with message "No such file or directory"

Just tried the client locally:

./target/debug/examples/tlsclient --http mozilla-modern.badssl.com
thread '<main>' panicked at 'called `Result::unwrap()` on an `Err` value: Error { repr: Os { code: 2, message: "No such file or directory" } }', ../src/libcore/result.rs:785
note: Run with `RUST_BACKTRACE=1` for a backtrace.

the rust version:

rustc --version
rustc 1.10.0 (cfcb716cf 2016-07-03)

I am using mac.

Performance: Use of `Mutex` for storring session state

Could the Mutex that wraps the session state stores be the responsiblity of the StoresClientSessions and StoresServerSessions trait implementors? This would then not penalise servers or clients running a Tls session on a single thread, and would allow for the possibility of multiple session stores, one per thread per listener on a server.

Can't compile with Rust 1.17

The attribute export_macro is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642)
--> /.cargo/registry/src/github.com/rustls-0.5.6/src/msgs/macros.rs:3:1
|
3 | #[export_macro]
| ^^^^^^^^^^^^^^^

error: aborting due to previous error

Performance: Review use of `assert!`

There are a number of places in the code paths through the code where assert! is used. Could these make use of debug_assert!? Many of the locations are far away from where a consumer of the library's API can have any influence or control input.

Add OCSP stapling support

I would like to help add OCSP stapling support to Rustls by adding the necessary primitives to webpki. I filed three issues:

  1. Client-side OCSP stapling support: briansmith/webpki#26.
  2. Server-side OCSP stapling support: briansmith/webpki#27.
  3. Must-Staple support: briansmith/webpki#28.

My plan is to do #1 first. I'm hoping the client-side code of Rustls can then be easily modified to pass staplied OCSP responses to webpki as part of certificate validation. Then I'll add #3, which shouldn't require any changes to Rustls.

I'm not sure how well BOGO tests OCSP stapling.

I am curious what @ctz and others think about adding OCSP stapling support to Rustls and if there are any non-obvious things to watch out for.

Ciphers supported for TLS1.2

I apologize for a naive question, I'm not a crypto expert. Looking at the list of all cipher suites:

pub static ALL_CIPHERSUITES: [&'static SupportedCipherSuite; 9] =
    [// TLS1.3 suites
     &TLS13_CHACHA20_POLY1305_SHA256,
     &TLS13_AES_256_GCM_SHA384,
     &TLS13_AES_128_GCM_SHA256,

     // TLS1.2 suites
     &TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
     &TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
     &TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
     &TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
     &TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
     &TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256];

I see that AES_256_GCM_SHA384 and AES_128_GCM_SHA256 are not supported without Diffie-Helman for TLS1.2. Are those configurations insecure? openssl has those ciphers defined.

I encountered a problem trying to build a library working with syslog-ng over TLS, and it doesn't support DH ciphers, at least in OSE version. I could probably work around it with native-tls, not sure I like the idea though, and since there is no TLS13 in openssl (at least not in any common version) I can't switch syslog-ng to it either.

Is my only option going back to native-tls?

How to complete handshake?

Could you please provide a simple example how to complete a handshake with rustls?

I'm trying this:

        while self.session.is_handshaking() {
            if self.session.wants_write() {
                self.session.write_tls(&mut self.stream)?;
            }
            if self.session.wants_read() {
                self.session.read_tls(&mut self.stream)?;
            }
            self.session.process_new_packets().expect("TODO");
        }

It hangs I have now idea why.

Add an extra parser to pemfile for general keys

I just did the following for test purposes:

$ openssl version
OpenSSL 1.0.2j  26 Sep 2016
$ openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes

And the output cannot be read by pemfile::rsa_private_key. The workaround is to do:

openssl rsa -in key.pem -out rsa_key.pem 

But it would probably be better if it worked out of the box. Also, I'm the author of Thrussh, an SSH library. How about working together on a general PEM parsing crate?

Test suite doesn't work on Windows

Output { status: ExitStatus(ExitStatus(101)), stdout: "", stderr: "thread \'main\' panicked at \'cannot open CA file \'/etc/ssl/certs/ca-certificates.crt\': Error { repr: Os { code: 3, message: \"The system cannot find the path specified.\" } }\nConsider using the --cafile option to provide a valid CA file.\', examples\\tlsclient.rs:408\nstack backtrace:\n   0:     0x7ff6a4b7137e - std::panicking::rust_panic_with_hook::h2224f33fb7bf2f4c\n   1:     0x7ff6a4b6fd21 - std::rt::lang_start::h352a66f5026f54bd\n   2:     0x7ff6a4b7075d - std::panicking::rust_panic_with_hook::h2224f33fb7bf2f4c\n   3:     0x7ff6a4b705f6 - std::panicking::begin_panic_fmt::h310416c62f3935b3\n   4:     0x7ff6a4b70504 - std::panicking::begin_panic_fmt::h310416c62f3935b3\n   5:     0x7ff6a4926ff8 - tlsclient::make_config\n                        at C:\\Users\\<...>\\rustls\\<std macros>:8\n   6:     0x7ff6a49279f0 - tlsclient::main\n       

Probably rustls should ship with a root CA file that contains the roots that are needed to pass the tests.

Bounded buffering

The docs for .write() mention that prior to handshake completion a ClientSession or ServerSession will buffer data without bound.

This is arguably sane, though I would prefer an interface that only allows calling .write() after a handshake has been completed, to present uniform buffering semantics throughout the lifetime of the session.

However, I'm curious what buffering behavior is after initial handshaking, e.g. if an application repeatedly calls .write() but never .write_tls(). Does data still buffer indefinitely inside the Session, or does .write() stop accepting new bytes at some point if none leave the Session as TLS records?

If .write() buffers indefinitely during the "moving traffic" stage of a TLS connection, is there a way to detect how much data is currently buffered so applications can provide backpressure for writers that outpace the network?

There are analogous questions about the behavior of .read_tls()/.read().

Thanks!

SessionId::len

Quick question about SessionID:

#[derive(Copy)]
pub struct SessionID {
    len: usize,
    data: [u8; 32],
}

Is there a reason why this is not simply a Vec?
Having a len field makes this data type a bit clumsy/non-rusty.

Protocol state should use a typed representation

AFAICT, the state of the TLS session is currently represented in a way that would allow the implementation to access/set data at inappropriate times in the protocol. Such state machine issues have lead to severe vulnerabilities such as CCS Injection, goto fail, SMACK, and many others.

Indeed, the handshake implementation acts directly on the session state (in SessionCommon, {Client,Server}HandshakeData, ...), implicitely relying on the implementation correctly setting fields to None or Some(_) depending on the protocol phase, instead of using a more constrained type that prevents having fields inconsistent with the protocol state.

This can be implemented in several ways in Rust with low to no overhead, incl. using session types, and experiences in other languages strongly suggest that this can prevent many issues.

I have started working on this, but I'm opening the issue so other people may comment (or take this up if I cannot find the time/energy to finish). It seems to be a pretty major refactoring effort, though.

BorrowMessage

While implementing DTLS I came accross BorrowMessage. What purpose does it have?
Is there a reason why not to simply pass a &Message?

Document read_tls returning 0

As far as I can tell from the source, whenever read_tls returns Ok(0), it means the socket was just closed. This might be obvious, but still should appear in the documentation.

RSASigner chokes on a valid private key

I've got a private key that openssl thinks is fine, but RSASigner does not like. Luckily it's not protecting anything anymore, so I can include it here :)

Example program:

extern crate rustls;

use rustls::PrivateKey;
use rustls::sign::RSASigner;

use std::fs::File;
use std::io::Read;

fn main() {
    let mut file = File::open("/tmp/test.der").unwrap();
    let mut buf = Vec::new();
    file.read_to_end(&mut buf).unwrap();

    let key = PrivateKey(buf);

    match RSASigner::new(&key) {
        Ok(_) => {
            println!("Key was okay");
        }
        Err(e) => {
            println!("Private key data was invalid: {:?}", e);
        }
    }
}

Which outputs Private key data was invalid: () when run on this key (but works fine on other keys)

The key:

-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEA2P6jXiRYufQCSVS6qsqmE1ZLQIcfcJMZjl5qg+a6VD9s71yh
0hxu0ow3Fzc7yeh3fvn+2sVFvlMlZ6pu0RVE1Qad4qvnRtEldRuQYcq4Qw6D/3Tq
veyNVsO7NaAl6Eu9yw3XNGdG7eqVyrrFUnYXJ0OipY6LnywCs35G7EAUrmW++dH0
ArndtEqb8uPrD7P2E7f4tU6TZaQpvZnPy/PVWUe8k4VeyEvQASIN6RSIj7gEMlXs
ye4jgFyQmZcvF7cko3/bhWSG6YD4/LmFyEx1gjQk6qEHRXm8j5W1CvSUG544GBne
LzoWIo87uuQAMXk/ZXtgMnHOetLO4lC8Q19VewIDAQABAoIBAHAPyOSUVrHpnsiq
FiCfuPahiQlQ/t6PSRJqFg36ON3LR4Gxz+wHPQBE4yp9HsZd5GBR0NjAKg1pORb5
QHN/zWVKHn1yE2VSG0sIKh8mptQSif6CLbxZjoBxYpwGEa2Od/yGME5iy5GQpTzm
CYNVcw2W80cWf2p7OwXhP9VAHq4U785ahK6x4H+hjMBJRoRy6Zeqz+w/xCyq56fv
xM3qIk8JqhDztU+Ln0x/bug3Xry/CcSsdZL2wxlZwfaD8NpB0GQbaDBfOXVTGdil
8rGLnN7hCUO9AJqpsCUyEVRkB4xBW3CgZU+DpBf6vSKstFsRZMSg32GCHVU7dh/6
TI8xqxkCgYEA4hjr+yqSmhRi5TF3LW36+7z0eDya+82rQcdqry358SRRu1/ZlAda
/N38Qvir0Cj385Jw2wX8HYverry0VJbsGz5OBCB1dXP6HQ81JBCR8oqgtX8anGvl
JsmQRte2gVVeFPe1VsDBxrmUKhZXUSpPwjGIr3OlvsIbeugCPcfxaN8CgYEA9bGF
8MmFREtB2ZS6wZjoSivjcoAhslI3qzmLf+jQU34/a0fiLKa3muYZ+ZDKsh9ZSljK
366BvJ1bU/osnSSuukrtQ88qZpJJvdU9EwTqcNr8L7+1jZArrN/hbB/LARhu1sjG
Fq9O2v8/D1Uo/cjzcFBaaA2rbpXVP4OcXDyWOuUCgYBtsK+T/BSBwhA0p2ntVWUl
ioeEacq7DQ3f7NJ6SLDw57DrWdYiNetTsJK5HxGj/KxGtC4iZGXrI7eWSKCoRUwo
73JEGEdEA089l+otJAjahZzwUMjlSIc06Scg53h4iKULQR3uB7g7JD+Yp5wXGZL2
YLeyf0XTJTLVzwd/V6hsOwKBgQDqNtgTaVhEeWWF0JWT9nsCMgJ55ZG510zASnQk
dEEcRs6YK4d9v1RqMo5ybUf9M4tAJ5MGVunQb0Vfsa6UAyMZ7lFuge/OpgfsEnpN
RjNjcC5WKnAdSmGIREg1db1lBvCqiezkNSx78jUgHbOc8tK2r7LvXJCfM/B8wq7s
8sjXzQKBgQCFtN2BRQj4oyl4itaQCGoWdRZLYJOY5G2tm/Gd+wHQK3FubrMJyZpC
IKhnvhlWh9ghNozMDPaCss22QQyxN2kQdD1oeR05R0bH50OTbnkqrm15hgNhqLGy
nV1B8Jh1Mo2CsI3HmIj9WhBo5Xmv1UqfKq3H30IVvtLSE+xa6qgTlQ==
-----END RSA PRIVATE KEY-----

Save that key as /tmp/test.key. Then convert to der with: openssl rsa -outform der -in test.key -out test.der. We can verify that the key is valid as:

$ openssl rsa -inform der -in /tmp/test.der -check
RSA key ok
writing RSA key
-----BEGIN RSA PRIVATE KEY-----
[snip, same as above]
-----END RSA PRIVATE KEY-----

Tests should dump and validate TLS traces

We have quite a few tests that produce actual TLS sessions:

  • api.rs seems to test rustls against itself;
  • many tests involve OpenSSL and rustls;
  • rustls is tested against badssl.com;
  • rustls is tested against a number of popular websites.

Each of those tests should dump the actual TLS session, ideally as a pcap file, and the session keys involved, so that the dumped trace can be automatically checked for protocol conformance.

The goal is to get stronger guarantees out of each test that gets written; as mentioned in #81, taking invalid transitions in the protocol is a major source of vulnerabilities.

Bump ring to 0.11

rustls is presently unusable with up-to-date libraries due to ring version incompatibilities. Please update the ring dependency to 0.11. You will also need to update the webpki dependency to 0.14 and webpki-roots to 0.11, which first needs to exist (rustls/webpki-roots#9). You may also wish to update base64 to 0.6.

Error for TLSError?

Right now I'm in the process of adding rustls as a backend for tokio-tls, and one part that'd be nice is the ability to convert a TLS error to a normal I/O error, e.g. through io::Error::new(io::ErrorKind::Other, tls_error). That requires an implementation of the Error trait for TLSError, though. Would you be open to adding that?

Disable cert verification for client certs?

I want to start by saying that I recognize that in many senses this goes against the spirit of this (excellent) library, so if there's no interest, I'll be understanding.

I've got a use case where I'd like to be able to accept truly any client cert. I've also had use cases in previous contexts where I'd really want to be able to bring my own cert verification as a typical verifier would present a challenge, the most recent of these was wanting to use SCVP for verification instead of doing it myself.

Client authentication is expecting `id-kp-serverAuth` instead of `id-kp-clientAuth`

Hello,

I have a server and a client that need to establish a TLS connection. I created two certs: one for the server with EKU=serverAuth and one for the client with EKU=clientAuth.

When I turned client authentication on I found that the server is rejecting clients with error WebPKIError(RequiredEKUNotFound). I traced the issue to webpki::verify_cert::check_eku. The function was looking for EKU [43, 6, 1, 5, 5, 7, 3, 1] (a.k.a id-kp-serverAuth) instead of EKU [43, 6, 1, 5, 5, 7, 3, 2] (a.k.a id-kp-clientAuth).

Note:
When the server and client both have EKU=serverAuth, client authentication works.
When the server has EKU=clientAuth and client has EKU=serverAuth client authentication fails on client side (RequiredEKUNotFound).

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.