Commit f2c69ae7 authored by Steven Fackler's avatar Steven Fackler
Browse files

Merge remote-tracking branch 'origin/master' into x509-builder

parents b3b7194e 3a0d24f7
Loading
Loading
Loading
Loading
+17 −14
Original line number Diff line number Diff line
@@ -9,10 +9,17 @@ env:
    - BUILD_OPENSSL_VERSION=1.0.1u
matrix:
  include:
    # osx 32/64
    - os: osx
      env: TARGET=x86_64-apple-darwin
    - os: osx
      env: TARGET=i686-apple-darwin
      install: brew uninstall openssl && brew install openssl --universal --without-test

    # ARM-bit version compat
    - env: >
        TARGET=arm-unknown-linux-gnueabihf
        BUILD_OPENSSL_VERSION=1.0.2h
        BUILD_OPENSSL_VERSION=1.0.2k
        CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_LINKER=arm-linux-gnueabihf-gcc
        QEMU_LD_PREFIX=/usr/arm-linux-gnueabihf
        RUST_TEST_THREADS=1
@@ -25,7 +32,7 @@ matrix:
            - binfmt-support
    - env: >
        TARGET=arm-unknown-linux-gnueabihf
        BUILD_OPENSSL_VERSION=1.1.0b
        BUILD_OPENSSL_VERSION=1.1.0d
        CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_LINKER=arm-linux-gnueabihf-gcc
        QEMU_LD_PREFIX=/usr/arm-linux-gnueabihf
        RUST_TEST_THREADS=1
@@ -38,15 +45,15 @@ matrix:
            - binfmt-support

    # Minimum version supported
    - rust: 1.9.0
    - rust: 1.10.0

    # beta/nightly channels
    - rust: beta
    - rust: nightly

    # 64-bit version compat
    - env: BUILD_OPENSSL_VERSION=1.0.2h
    - env: BUILD_OPENSSL_VERSION=1.1.0b
    - env: BUILD_OPENSSL_VERSION=1.0.2k
    - env: BUILD_OPENSSL_VERSION=1.1.0d

    # 32-bit version compat
    - env: TARGET=i686-unknown-linux-gnu BUILD_OPENSSL_VERSION=1.0.1u
@@ -54,24 +61,19 @@ matrix:
        apt:
          packages:
            - gcc-multilib
    - env: TARGET=i686-unknown-linux-gnu BUILD_OPENSSL_VERSION=1.0.2h
    - env: TARGET=i686-unknown-linux-gnu BUILD_OPENSSL_VERSION=1.0.2k
      addons:
        apt:
          packages:
            - gcc-multilib
    - env: TARGET=i686-unknown-linux-gnu BUILD_OPENSSL_VERSION=1.1.0b
    - env: TARGET=i686-unknown-linux-gnu BUILD_OPENSSL_VERSION=1.1.0d
      addons:
        apt:
          packages:
            - gcc-multilib

    # osx 32/64
    - os: osx
      env: TARGET=x86_64-apple-darwin
    - os: osx
      env: TARGET=i686-apple-darwin
      install: brew uninstall openssl && brew install openssl --universal

    # LibreSSL
    - env: BUILD_LIBRESSL_VERSION=2.5.0

before_install:
  - ./openssl/test/build.sh
@@ -83,4 +85,5 @@ script:
cache:
  cargo: true
  directories:
    - $HOME/libressl
    - $HOME/openssl
+37 −10
Original line number Diff line number Diff line
@@ -2,18 +2,18 @@

[![Build Status](https://travis-ci.org/sfackler/rust-openssl.svg?branch=master)](https://travis-ci.org/sfackler/rust-openssl)

[Documentation](https://sfackler.github.io/rust-openssl/doc/v0.9.0/openssl).
[Documentation](https://docs.rs/openssl).

## Warning

This README does not correspond to rust-openssl 0.7.x. See
This README does not correspond to rust-openssl 0.7.x or 0.8.x. See
[here](https://github.com/sfackler/rust-openssl/blob/b8fb29db5c246175a096260eacca38180cd77dd0/README.md)
for that README.

## Building

rust-openssl depends on the OpenSSL runtime libraries version 1.0.1 or above.
Currently the libraries need to be present in the build environment before this
rust-openssl depends on OpenSSL version 1.0.1 or above, or LibreSSL. Both the
libraries and headers need to be present in the build environment before this
crate is compiled, and some instructions of how to do this are in the sections
below.

@@ -37,9 +37,9 @@ compiling to a separate target, you'll typically need to compile OpenSSL from
source. That can normally be done with:

```
curl -O https://www.openssl.org/source/openssl-1.1.0b.tar.gz
tar xf openssl-1.1.0b.tar.gz
cd openssl-1.1.0b
curl -O https://www.openssl.org/source/openssl-1.1.0c.tar.gz
tar xf openssl-1.1.0c.tar.gz
cd openssl-1.1.0c
export CC=...
./Configure --prefix=... linux-x86_64 -fPIC
make -j$(nproc)
@@ -49,20 +49,29 @@ make install
### OSX

Although OpenSSL 0.9.8 is preinstalled on OSX this library is being phased out
of OSX and this crate also does not support this version of OpenSSL. To use this
of OSX and this crate also does not support that version of OpenSSL. To use this
crate on OSX you'll need to install OpenSSL via some alternate means, typically
homebrew:
Homebrew:

```bash
brew install openssl
```

> Occasionally an update of XCode or MacOS will cause the linker to fail after compilation, to rectify this you may want to try and run:

```bash
xcode-select --install
```

If Homebrew is installed to the default location of `/usr/local`, OpenSSL will be
automatically detected.

### Windows MSVC

On MSVC it's unfortunately not always a trivial process acquiring OpenSSL.
Perhaps the easiest way to do this right now is to download [precompiled
binaries] and install them on your system. Currently it's recommended to
install the 1.1.0b light installation if you're choosing this route.
install the 1.1.0 (non-light) installation if you're choosing this route.

[precompiled binaries]: http://slproweb.com/products/Win32OpenSSL.html

@@ -73,6 +82,18 @@ installation via an environment variable:
set OPENSSL_DIR=C:\OpenSSL-Win64
```

Note that this OpenSSL distribution does not ship with any root certificates.
So to make requests to servers on the internet, you have to install them
manually. Download the [cacert.pem file from here], copy it somewhere safe
(`C:\OpenSSL-Win64\certs` is a good place) and point the `SSL_CERT_FILE`
environment variable there:

```
set SSL_CERT_FILE=C:\OpenSSL-Win64\certs\cacert.pem
```

[cacert.pem file from here]: https://curl.haxx.se/docs/caextract.html

After that, you're just a `cargo build` away!

### Windows GNU (MinGW)
@@ -102,6 +123,12 @@ The build script can be configured via environment variables:
* `OPENSSL_DIR` - If specified, a directory that will be used to find
  OpenSSL installation. It's expected that under this directory the `include`
  folder has header files and a `lib` folder has the runtime libraries.
* `OPENSSL_LIB_DIR` - If specified, a directory that will be used to find
  OpenSSL libraries. Overrides the `lib` folder implied by `OPENSSL_DIR`
  (if specified).
* `OPENSSL_INCLUDE_DIR` - If specified, a directory that will be used to find
  OpenSSL header files. Overrides the `include` folder implied by `OPENSSL_DIR`
  (if specified).
* `OPENSSL_STATIC` - If specified, OpenSSL libraries will be statically rather
  than dynamically linked.

+4 −4
Original line number Diff line number Diff line
@@ -5,20 +5,20 @@ environment:
    - TARGET: i686-pc-windows-gnu
      BITS: 32
      MSYS2: 1
      OPENSSL_VERSION: 1_1_0b
      OPENSSL_VERSION: 1_1_0d
    - TARGET: x86_64-pc-windows-msvc
      BITS: 64
      OPENSSL_VERSION: 1_1_0b
      OPENSSL_VERSION: 1_1_0d
      OPENSSL_DIR: C:\OpenSSL

    # 1.0.2, 64/32 bit
    - TARGET: x86_64-pc-windows-gnu
      BITS: 64
      MSYS2: 1
      OPENSSL_VERSION: 1_0_2j
      OPENSSL_VERSION: 1_0_2k
    - TARGET: i686-pc-windows-msvc
      BITS: 32
      OPENSSL_VERSION: 1_0_2j
      OPENSSL_VERSION: 1_0_2k
      OPENSSL_DIR: C:\OpenSSL
install:
  # install OpenSSL
+9 −3
Original line number Diff line number Diff line
[package]
name = "openssl-sys"
version = "0.9.0"
version = "0.9.6"
authors = ["Alex Crichton <alex@alexcrichton.com>",
           "Steven Fackler <sfackler@gmail.com>"]
license = "MIT"
description = "FFI bindings to OpenSSL"
repository = "https://github.com/sfackler/rust-openssl"
documentation = "https://sfackler.github.io/rust-openssl/doc/v0.9.0/openssl_sys"
documentation = "https://docs.rs/openssl-sys/0.9.6/openssl_sys"
categories = ["cryptography", "external-ffi-bindings"]
links = "openssl"
build = "build.rs"

@@ -14,8 +15,13 @@ build = "build.rs"
libc = "0.2"

[build-dependencies]
pkg-config = "0.3"
pkg-config = "0.3.9"
gcc = "0.3.42"

[target.'cfg(windows)'.dependencies]
user32-sys = "0.2"
gdi32-sys = "0.2"

# We don't actually use metadeps for annoying reasons but this is still here for tooling
[package.metadata.pkg-config]
openssl = "1.0.1"
+148 −140
Original line number Diff line number Diff line
extern crate pkg_config;
extern crate gcc;

use std::collections::HashSet;
use std::env;
use std::ffi::OsString;
use std::fs::File;
use std::io::Read;
use std::io::{BufWriter, Write};
use std::path::{Path, PathBuf};
use std::panic::{self, AssertUnwindSafe};
use std::process::Command;

// The set of `OPENSSL_NO_<FOO>`s that we care about.
const DEFINES: &'static [&'static str] = &[
    "OPENSSL_NO_BUF_FREELISTS",
    "OPENSSL_NO_COMP",
    "OPENSSL_NO_EC",
    "OPENSSL_NO_ENGINE",
    "OPENSSL_NO_KRB5",
    "OPENSSL_NO_NEXTPROTONEG",
    "OPENSSL_NO_PSK",
    "OPENSSL_NO_RFC3779",
    "OPENSSL_NO_SHA",
    "OPENSSL_NO_SRP",
    "OPENSSL_NO_SSL3_METHOD",
    "OPENSSL_NO_TLSEXT",
];

enum Version {
    Openssl110,
    Openssl102,
    Openssl101,
    Libressl,
}

fn main() {
    let target = env::var("TARGET").unwrap();

    let lib_dir = env::var_os("OPENSSL_LIB_DIR").map(PathBuf::from);
    let include_dir = env::var_os("OPENSSL_INCLUDE_DIR").map(PathBuf::from);

    let (lib_dir, include_dir) = if lib_dir.is_none() || include_dir.is_none() {
        let openssl_dir = env::var_os("OPENSSL_DIR").unwrap_or_else(|| {
            find_openssl_dir(&target)
        });
        let openssl_dir = Path::new(&openssl_dir);
        let lib_dir = lib_dir.unwrap_or_else(|| openssl_dir.join("lib"));
        let include_dir = include_dir.unwrap_or_else(|| openssl_dir.join("include"));
        (lib_dir, include_dir)
    } else {
        (lib_dir.unwrap(), include_dir.unwrap())
    };

    let lib_dir = Path::new(&openssl_dir).join("lib");
    let include_dir = Path::new(&openssl_dir).join("include");
    if !Path::new(&lib_dir).exists() {
        panic!("OpenSSL library directory does not exist: {}",
               lib_dir.to_string_lossy());
    }

    if !Path::new(&include_dir).exists() {
        panic!("OpenSSL include directory does not exist: {}",
               include_dir.to_string_lossy());
@@ -30,17 +63,14 @@ fn main() {
    println!("cargo:rustc-link-search=native={}", lib_dir.to_string_lossy());
    println!("cargo:include={}", include_dir.to_string_lossy());

    let version = validate_headers(&[include_dir.clone().into()],
                                   &[lib_dir.clone().into()]);
    let version = validate_headers(&[include_dir.clone().into()]);

    let libs = if (version.contains("0x10001") ||
                   version.contains("0x10002")) &&
                  target.contains("windows") {
    let libs = match version {
        Version::Openssl101 | Version::Openssl102 if target.contains("windows") => {
            ["ssleay32", "libeay32"]
    } else if target.contains("windows") {
        ["libssl", "libcrypto"]
    } else {
        ["ssl", "crypto"]
        }
        Version::Openssl110 if target.contains("windows") => ["libssl", "libcrypto"],
        _ => ["ssl", "crypto"],
    };

    let kind = determine_mode(Path::new(&lib_dir), &libs);
@@ -160,29 +190,12 @@ fn try_pkg_config() {
        return
    }

    // We're going to be looking at header files, so show us all the system
    // cflags dirs for showing us lots of `-I`.
    env::set_var("PKG_CONFIG_ALLOW_SYSTEM_CFLAGS", "1");

    let lib = match pkg_config::find_library("openssl") {
        Ok(lib) => lib,
        Err(_) => return,
    };

    if lib.include_paths.len() == 0 {
        panic!("

Used pkg-config to discover the OpenSSL installation, but pkg-config did not
return any include paths for the installation. This crate needs to take a peek
at the header files so it cannot proceed unless they're found.

You can try fixing this by setting the `OPENSSL_DIR` environment variable
pointing to your OpenSSL installation.

");
    }
    let lib = pkg_config::Config::new()
        .print_system_libs(false)
        .find("openssl")
        .unwrap();

    validate_headers(&lib.include_paths, &lib.link_paths);
    validate_headers(&lib.include_paths);

    for include in lib.include_paths.iter() {
        println!("cargo:include={}", include.display());
@@ -193,65 +206,11 @@ pointing to your OpenSSL installation.

/// Validates the header files found in `include_dir` and then returns the
/// version string of OpenSSL.
fn validate_headers(include_dirs: &[PathBuf],
                    libdirs: &[PathBuf]) -> String {
fn validate_headers(include_dirs: &[PathBuf]) -> Version {
    // This `*-sys` crate only works with OpenSSL 1.0.1, 1.0.2, and 1.1.0. To
    // correctly expose the right API from this crate, take a look at
    // `opensslv.h` to see what version OpenSSL claims to be.
    let mut version_header = String::new();
    let mut include = include_dirs.iter()
                                  .map(|p| p.join("openssl/opensslv.h"))
                                  .filter(|p| p.exists());
    let mut f = match include.next() {
        Some(f) => File::open(f).unwrap(),
        None => {
            panic!("failed to open header file at `openssl/opensslv.h` to learn
                    about OpenSSL's version number, looked inside:\n\n{:#?}\n\n",
                   include_dirs);
        }
    };
    f.read_to_string(&mut version_header).unwrap();

    // Do a bit of string parsing to find `#define OPENSSL_VERSION_NUMBER ...`
    let version_line = version_header.lines().find(|l| {
        l.contains("define ") && l.contains("OPENSSL_VERSION_NUMBER")
    }).and_then(|line| {
        let start = match line.find("0x") {
            Some(start) => start,
            None => return None,
        };
        Some(line[start..].trim())
    });
    let version_text = match version_line {
        Some(text) => text,
        None => {
            panic!("header file at `{}` did not include `OPENSSL_VERSION_NUMBER` \
                    that this crate recognized, failed to learn about the \
                    OpenSSL version number");
        }
    };
    if version_text.contains("0x10001") {
        println!("cargo:rustc-cfg=ossl101");
        println!("cargo:version=101");
    } else if version_text.contains("0x10002") {
        println!("cargo:rustc-cfg=ossl102");
        println!("cargo:version=102");
    } else if version_text.contains("0x10100") {
        println!("cargo:rustc-cfg=ossl110");
        println!("cargo:version=110");
    } else {
        panic!("

This crate is only compatible with OpenSSL 1.0.1, 1.0.2, and 1.1.0, but a
different version of OpenSSL was found:

    {}

The build is now aborting due to this version mismatch.

", version_text);
    }

    //
    // OpenSSL has a number of build-time configuration options which affect
    // various structs and such. Since OpenSSL 1.1.0 this isn't really a problem
    // as the library is much more FFI-friendly, but 1.0.{1,2} suffer this problem.
@@ -260,56 +219,105 @@ The build is now aborting due to this version mismatch.
    // file of OpenSSL, `opensslconf.h`, and then dump out everything it defines
    // as our own #[cfg] directives. That way the `ossl10x.rs` bindings can
    // account for compile differences and such.
    let mut conf_header = String::new();
    let mut include = include_dirs.iter()
                                  .map(|p| p.join("openssl/opensslconf.h"))
                                  .filter(|p| p.exists());
    let mut f = match include.next() {
        Some(f) => File::open(f).unwrap(),
        None => {
            // It's been seen that on linux the include dir printed out by
            // `pkg-config` doesn't actually have opensslconf.h. Instead
            // it's in an architecture-specific include directory.
            //
            // Try to detect that case to see if it exists.
            let mut libdirs = libdirs.iter().map(|p| {
                p.iter()
                 .map(|p| if p == "lib" {"include".as_ref()} else {p})
                 .collect::<PathBuf>()
            }).map(|p| {
                p.join("openssl/opensslconf.h")
            }).filter(|p| p.exists());
            match libdirs.next() {
                Some(f) => File::open(f).unwrap(),
                None => {
                    panic!("failed to open header file at
                            `openssl/opensslconf.h` to learn about \
                            OpenSSL's version number, looked \
                            inside:\n\n{:#?}\n\n",
                           include_dirs);
    let mut path = PathBuf::from(env::var_os("OUT_DIR").unwrap());
    path.push("expando.c");
    let mut file = BufWriter::new(File::create(&path).unwrap());

    write!(file, "\
#include <openssl/opensslv.h>
#include <openssl/opensslconf.h>

#ifdef LIBRESSL_VERSION_NUMBER
RUST_LIBRESSL
#elif OPENSSL_VERSION_NUMBER >= 0x10200000
RUST_OPENSSL_NEW
#elif OPENSSL_VERSION_NUMBER >= 0x10100000
RUST_OPENSSL_110
#elif OPENSSL_VERSION_NUMBER >= 0x10002000
RUST_OPENSSL_102
#elif OPENSSL_VERSION_NUMBER >= 0x10001000
RUST_OPENSSL_101
#else
RUST_OPENSSL_OLD
#endif
").unwrap();

    for define in DEFINES {
        write!(file, "\
#ifdef {define}
RUST_{define}
#endif
", define = define).unwrap();
    }

    file.flush().unwrap();
    drop(file);

    let mut gcc = gcc::Config::new();
    for include_dir in include_dirs {
        gcc.include(include_dir);
    }
    // https://github.com/alexcrichton/gcc-rs/issues/133
    let expanded = match panic::catch_unwind(AssertUnwindSafe(|| gcc.file(&path).expand())) {
        Ok(expanded) => expanded,
        Err(_) => {
            panic!("
Failed to find OpenSSL development headers.

You can try fixing this setting the `OPENSSL_DIR` environment variable
pointing to your OpenSSL installation or installing OpenSSL headers package
specific to your distribution:

    # On Ubuntu
    sudo apt-get install libssl-dev
    # On Arch Linux
    sudo pacman -S openssl
    # On Fedora
    sudo dnf install openssl-devel

See rust-openssl README for more information:

    https://github.com/sfackler/rust-openssl#linux
");
        }
    };
    f.read_to_string(&mut conf_header).unwrap();

    // Look for `#define OPENSSL_FOO`, print out everything as our own
    // #[cfg] flag.
    let mut vars = vec![];
    for line in conf_header.lines() {
        let i = match line.find("define ") {
            Some(i) => i,
            None => continue,
        };
        let var = line[i + "define ".len()..].trim();
        if var.starts_with("OPENSSL") && !var.contains(" ") {
            println!("cargo:rustc-cfg=osslconf=\"{}\"", var);
            vars.push(var);
    let expanded = String::from_utf8(expanded).unwrap();

    let mut enabled = vec![];
    for &define in DEFINES {
        if expanded.contains(&format!("RUST_{}", define)) {
            println!("cargo:rustc-cfg=osslconf=\"{}\"", define);
            enabled.push(define);
        }
    }
    println!("cargo:conf={}", vars.join(","));
    println!("cargo:conf={}", enabled.join(","));

    return version_text.to_string()
    if expanded.contains("RUST_LIBRESSL") {
        println!("cargo:rustc-cfg=libressl");
        println!("cargo:libressl=true");
        println!("cargo:version=101");
        Version::Libressl
    } else if expanded.contains("RUST_OPENSSL_110") {
        println!("cargo:rustc-cfg=ossl110");
        println!("cargo:version=110");
        Version::Openssl110
    } else if expanded.contains("RUST_OPENSSL_102") {
        println!("cargo:rustc-cfg=ossl102");
        println!("cargo:version=102");
        Version::Openssl102
    } else if expanded.contains("RUST_OPENSSL_101") {
        println!("cargo:rustc-cfg=ossl101");
        println!("cargo:version=101");
        Version::Openssl101
    } else {
        panic!("

This crate is only compatible with OpenSSL 1.0.1, 1.0.2, and 1.1.0, or LibreSSL,
but a different version of OpenSSL was found. The build is now aborting due to
this version mismatch.

");
    }
}

/// Given a libdir for OpenSSL (where artifacts are located) as well as the name
Loading