Merge branch 'master' into common-crypto-backend

* master: (24 commits)
  Expose the innards of DH and DSA
  More bindings for asymmetric stuff
  Tell cffi these opaque types are pointers.
  rename variable to be less confusing and terrible
  Document when the common crypto bindings were added
  Expose a name needed for ECDHE -- the NIDs are always available
  Expose the nids for the various eliptical curve things. I don't understand what these mean.
  Specify the epub theme to fix the epub build on RTD.
  Added forgotten decl
  reversed
  Allow these to not be defined because lololol fedora/centos
  add conditional ERR_remove_thread_state. PyOpenSSL uses this
  Don't require sphinx spelling to be installed, for readthedocs benefit
  This is also a requirement
  oops
  Start binding some stuff for ECDHE in pyOpenSSL.
  check if openssl is installed via homebrew on osx. install if not
  Verify the tag len for GCM
  remove comment that's no longer needed
  Make just one call to ffi.cdef for most of the definitions
  ...
diff --git a/.travis.yml b/.travis.yml
index babea99..a70bb8c 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -30,10 +30,10 @@
     - ./.travis/install.sh
 
 script:
-    - if [[ "$(uname -s)" == "Darwin" ]]; then eval "$(pyenv init -)"; fi && source ~/.venv/bin/activate && tox -e $TOX_ENV
+    - ./.travis/run.sh
 
 after_success:
-    - coveralls
+    - source ~/.venv/bin/activate && coveralls
 
 notifications:
     irc:
@@ -64,21 +64,6 @@
           env: TOX_ENV=pypy
           compiler: gcc
         - os: osx
-          env: TOX_ENV=py26
-          compiler: clang
-        - os: osx
-          env: TOX_ENV=py27
-          compiler: clang
-        - os: osx
-          env: TOX_ENV=py32
-          compiler: clang
-        - os: osx
-          env: TOX_ENV=py33
-          compiler: clang
-        - os: osx
-          env: TOX_ENV=pypy
-          compiler: clang
-        - os: osx
           env: TOX_ENV=py26 OPENSSL=0.9.8
           compiler: gcc
         - os: osx
diff --git a/.travis/install.sh b/.travis/install.sh
index e6ea253..1e3b170 100755
--- a/.travis/install.sh
+++ b/.travis/install.sh
@@ -3,10 +3,17 @@
 set -e
 set -x
 
-if [[ "${OPENSSL}" == "0.9.8" && "$(uname -s)" != "Darwin" ]]; then
-    sudo add-apt-repository "deb http://archive.ubuntu.com/ubuntu/ lucid main"
-    sudo apt-get -y update
-    sudo apt-get install -y --force-yes libssl-dev/lucid
+if [[ "${OPENSSL}" == "0.9.8" ]]; then
+    if [[ "$(uname -s)" != "Darwin" ]]; then
+        sudo add-apt-repository "deb http://archive.ubuntu.com/ubuntu/ lucid main"
+        sudo apt-get -y update
+        sudo apt-get install -y --force-yes libssl-dev/lucid
+    else
+        # travis has openssl installed via brew already, but let's be sure
+        if [[ "$(brew list | grep openssl)" != "openssl" ]]; then
+            brew install openssl
+        fi
+    fi
 fi
 
 if [[ "${TOX_ENV}" == "docs" && "$(name -s)" != "Darwin" ]]; then
diff --git a/.travis/run.sh b/.travis/run.sh
new file mode 100755
index 0000000..4c01d67
--- /dev/null
+++ b/.travis/run.sh
@@ -0,0 +1,16 @@
+#!/bin/bash
+
+set -e
+set -x
+
+if [[ "$(uname -s)" == "Darwin" ]]; then
+    eval "$(pyenv init -)"
+    if [[ "${OPENSSL}" != "0.9.8" ]]; then
+        # so set our flags to use homebrew openssl
+        export ARCHFLAGS="-arch x86_64"
+        export LDFLAGS="-L/usr/local/opt/openssl/lib"
+        export CFLAGS="-I/usr/local/opt/openssl/include"
+    fi
+fi
+source ~/.venv/bin/activate
+tox -e $TOX_ENV
diff --git a/cryptography/hazmat/bindings/openssl/bignum.py b/cryptography/hazmat/bindings/openssl/bignum.py
index 59efd17..6545f32 100644
--- a/cryptography/hazmat/bindings/openssl/bignum.py
+++ b/cryptography/hazmat/bindings/openssl/bignum.py
@@ -47,6 +47,9 @@
 int BN_hex2bn(BIGNUM **, const char *);
 int BN_dec2bn(BIGNUM **, const char *);
 
+int BN_bn2bin(const BIGNUM *, unsigned char *);
+BIGNUM *BN_bin2bn(const unsigned char *, int, BIGNUM *);
+
 int BN_num_bits(const BIGNUM *);
 """
 
diff --git a/cryptography/hazmat/bindings/openssl/binding.py b/cryptography/hazmat/bindings/openssl/binding.py
index 8a4e1dd..88299d1 100644
--- a/cryptography/hazmat/bindings/openssl/binding.py
+++ b/cryptography/hazmat/bindings/openssl/binding.py
@@ -48,6 +48,7 @@
         "crypto",
         "dh",
         "dsa",
+        "ec",
         "engine",
         "err",
         "evp",
diff --git a/cryptography/hazmat/bindings/openssl/crypto.py b/cryptography/hazmat/bindings/openssl/crypto.py
index 189867b..40d91bf 100644
--- a/cryptography/hazmat/bindings/openssl/crypto.py
+++ b/cryptography/hazmat/bindings/openssl/crypto.py
@@ -16,6 +16,8 @@
 """
 
 TYPES = """
+typedef ... CRYPTO_THREADID;
+
 static const int SSLEAY_VERSION;
 static const int SSLEAY_CFLAGS;
 static const int SSLEAY_PLATFORM;
diff --git a/cryptography/hazmat/bindings/openssl/dh.py b/cryptography/hazmat/bindings/openssl/dh.py
index 3c12fbc..edbe0e3 100644
--- a/cryptography/hazmat/bindings/openssl/dh.py
+++ b/cryptography/hazmat/bindings/openssl/dh.py
@@ -16,7 +16,13 @@
 """
 
 TYPES = """
-typedef ... DH;
+typedef struct dh_st {
+    BIGNUM *p;              // prime number (shared)
+    BIGNUM *g;              // generator of Z_p (shared)
+    BIGNUM *priv_key;       // private DH value x
+    BIGNUM *pub_key;        // public DH value g^x
+    ...;
+} DH;
 """
 
 FUNCTIONS = """
diff --git a/cryptography/hazmat/bindings/openssl/dsa.py b/cryptography/hazmat/bindings/openssl/dsa.py
index 3b77d7a..9068e05 100644
--- a/cryptography/hazmat/bindings/openssl/dsa.py
+++ b/cryptography/hazmat/bindings/openssl/dsa.py
@@ -16,7 +16,14 @@
 """
 
 TYPES = """
-typedef ... DSA;
+typedef struct dsa_st {
+    BIGNUM *p;              // prime number (public)
+    BIGNUM *q;              // 160-bit subprime, q | p-1 (public)
+    BIGNUM *g;              // generator of subgroup (public)
+    BIGNUM *priv_key;       // private key x
+    BIGNUM *pub_key;        // public key y = g^x
+    ...;
+} DSA;
 """
 
 FUNCTIONS = """
diff --git a/cryptography/hazmat/bindings/openssl/ec.py b/cryptography/hazmat/bindings/openssl/ec.py
new file mode 100644
index 0000000..9f10365
--- /dev/null
+++ b/cryptography/hazmat/bindings/openssl/ec.py
@@ -0,0 +1,56 @@
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+INCLUDES = """
+#include <openssl/ec.h>
+#include <openssl/obj_mac.h>
+"""
+
+TYPES = """
+static const int Cryptography_HAS_EC;
+
+typedef ... EC_KEY;
+
+static const int NID_X9_62_prime192v1;
+static const int NID_X9_62_prime192v2;
+static const int NID_X9_62_prime192v3;
+static const int NID_X9_62_prime239v1;
+static const int NID_X9_62_prime239v2;
+static const int NID_X9_62_prime239v3;
+static const int NID_X9_62_prime256v1;
+"""
+
+FUNCTIONS = """
+EC_KEY *EC_KEY_new_by_curve_name(int);
+void EC_KEY_free(EC_KEY *);
+"""
+
+MACROS = """
+"""
+
+CUSTOMIZATIONS = """
+#ifdef OPENSSL_NO_EC
+static const long Cryptography_HAS_EC = 0;
+EC_KEY* (*EC_KEY_new_by_curve_name)(int) = NULL;
+void (*EC_KEY_free)(EC_KEY *) = NULL;
+#else
+static const long Cryptography_HAS_EC = 1;
+#endif
+"""
+
+CONDITIONAL_NAMES = {
+    "Cryptography_HAS_EC": [
+        "EC_KEY_new_by_curve_name",
+        "EC_KEY_free",
+    ],
+}
diff --git a/cryptography/hazmat/bindings/openssl/engine.py b/cryptography/hazmat/bindings/openssl/engine.py
index 390bfde..77118e8 100644
--- a/cryptography/hazmat/bindings/openssl/engine.py
+++ b/cryptography/hazmat/bindings/openssl/engine.py
@@ -24,11 +24,11 @@
 typedef ... DH_METHOD;
 typedef ... RAND_METHOD;
 typedef ... STORE_METHOD;
-typedef ... ENGINE_GEN_INT_FUNC_PTR;
-typedef ... ENGINE_CTRL_FUNC_PTR;
-typedef ... ENGINE_LOAD_KEY_PTR;
-typedef ... ENGINE_CIPHERS_PTR;
-typedef ... ENGINE_DIGESTS_PTR;
+typedef ... *ENGINE_GEN_INT_FUNC_PTR;
+typedef ... *ENGINE_CTRL_FUNC_PTR;
+typedef ... *ENGINE_LOAD_KEY_PTR;
+typedef ... *ENGINE_CIPHERS_PTR;
+typedef ... *ENGINE_DIGESTS_PTR;
 typedef ... ENGINE_CMD_DEFN;
 typedef ... UI_METHOD;
 
diff --git a/cryptography/hazmat/bindings/openssl/err.py b/cryptography/hazmat/bindings/openssl/err.py
index 1b66bd2..ddb60ef 100644
--- a/cryptography/hazmat/bindings/openssl/err.py
+++ b/cryptography/hazmat/bindings/openssl/err.py
@@ -16,24 +16,166 @@
 """
 
 TYPES = """
+static const int Cryptography_HAS_REMOVE_THREAD_STATE;
+
 struct ERR_string_data_st {
     unsigned long error;
     const char *string;
 };
 typedef struct ERR_string_data_st ERR_STRING_DATA;
 
-static const int ASN1_R_BAD_PASSWORD_READ;
 
 static const int ERR_LIB_EVP;
 static const int ERR_LIB_PEM;
+static const int ERR_LIB_ASN1;
 
+static const int ASN1_F_ASN1_ENUMERATED_TO_BN;
+static const int ASN1_F_ASN1_EX_C2I;
+static const int ASN1_F_ASN1_FIND_END;
+static const int ASN1_F_ASN1_GENERALIZEDTIME_SET;
+static const int ASN1_F_ASN1_GENERATE_V3;
+static const int ASN1_F_ASN1_GET_OBJECT;
+static const int ASN1_F_ASN1_ITEM_I2D_FP;
+static const int ASN1_F_ASN1_ITEM_PACK;
+static const int ASN1_F_ASN1_ITEM_SIGN;
+static const int ASN1_F_ASN1_ITEM_UNPACK;
+static const int ASN1_F_ASN1_ITEM_VERIFY;
+static const int ASN1_F_ASN1_MBSTRING_NCOPY;
+static const int ASN1_F_ASN1_TEMPLATE_EX_D2I;
+static const int ASN1_F_ASN1_TEMPLATE_NEW;
+static const int ASN1_F_ASN1_TEMPLATE_NOEXP_D2I;
+static const int ASN1_F_ASN1_TIME_SET;
+static const int ASN1_F_ASN1_TYPE_GET_INT_OCTETSTRING;
+static const int ASN1_F_ASN1_TYPE_GET_OCTETSTRING;
+static const int ASN1_F_ASN1_UNPACK_STRING;
+static const int ASN1_F_ASN1_UTCTIME_SET;
+static const int ASN1_F_ASN1_VERIFY;
+static const int ASN1_F_B64_READ_ASN1;
+static const int ASN1_F_B64_WRITE_ASN1;
+static const int ASN1_F_BITSTR_CB;
+static const int ASN1_F_BN_TO_ASN1_ENUMERATED;
+static const int ASN1_F_BN_TO_ASN1_INTEGER;
+static const int ASN1_F_D2I_ASN1_TYPE_BYTES;
+static const int ASN1_F_D2I_ASN1_UINTEGER;
+static const int ASN1_F_D2I_ASN1_UTCTIME;
+static const int ASN1_F_D2I_NETSCAPE_RSA;
+static const int ASN1_F_D2I_NETSCAPE_RSA_2;
+static const int ASN1_F_D2I_PRIVATEKEY;
+static const int ASN1_F_D2I_X509;
+static const int ASN1_F_D2I_X509_CINF;
+static const int ASN1_F_D2I_X509_PKEY;
+static const int ASN1_F_I2D_ASN1_SET;
+static const int ASN1_F_I2D_ASN1_TIME;
+static const int ASN1_F_I2D_DSA_PUBKEY;
+static const int ASN1_F_LONG_C2I;
+static const int ASN1_F_OID_MODULE_INIT;
+static const int ASN1_F_PARSE_TAGGING;
+static const int ASN1_F_PKCS5_PBE_SET;
+static const int ASN1_F_SMIME_READ_ASN1;
+static const int ASN1_F_SMIME_TEXT;
+static const int ASN1_F_X509_CINF_NEW;
+static const int ASN1_R_BOOLEAN_IS_WRONG_LENGTH;
+static const int ASN1_R_BUFFER_TOO_SMALL;
+static const int ASN1_R_CIPHER_HAS_NO_OBJECT_IDENTIFIER;
+static const int ASN1_R_DATA_IS_WRONG;
+static const int ASN1_R_DECODE_ERROR;
+static const int ASN1_R_DECODING_ERROR;
+static const int ASN1_R_DEPTH_EXCEEDED;
+static const int ASN1_R_ENCODE_ERROR;
+static const int ASN1_R_ERROR_GETTING_TIME;
+static const int ASN1_R_ERROR_LOADING_SECTION;
+static const int ASN1_R_MSTRING_WRONG_TAG;
+static const int ASN1_R_NESTED_ASN1_STRING;
+static const int ASN1_R_NO_CONTENT_TYPE;
+static const int ASN1_R_NO_MATCHING_CHOICE_TYPE;
+static const int ASN1_R_NO_MULTIPART_BODY_FAILURE;
+static const int ASN1_R_NO_MULTIPART_BOUNDARY;
+static const int ASN1_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM;
+static const int ASN1_R_UNKNOWN_OBJECT_TYPE;
+static const int ASN1_R_UNKNOWN_PUBLIC_KEY_TYPE;
+static const int ASN1_R_UNKNOWN_TAG;
+static const int ASN1_R_UNKOWN_FORMAT;
+static const int ASN1_R_UNSUPPORTED_ANY_DEFINED_BY_TYPE;
+static const int ASN1_R_UNSUPPORTED_ENCRYPTION_ALGORITHM;
+static const int ASN1_R_UNSUPPORTED_PUBLIC_KEY_TYPE;
+static const int ASN1_R_UNSUPPORTED_TYPE;
+static const int ASN1_R_WRONG_TAG;
+static const int ASN1_R_WRONG_TYPE;
+
+static const int EVP_F_AES_INIT_KEY;
+static const int EVP_F_CAMELLIA_INIT_KEY;
+static const int EVP_F_D2I_PKEY;
+static const int EVP_F_DSA_PKEY2PKCS8;
+static const int EVP_F_DSAPKEY2PKCS8;
+static const int EVP_F_ECDSA_PKEY2PKCS8;
+static const int EVP_F_ECKEY_PKEY2PKCS8;
+static const int EVP_F_EVP_CIPHER_CTX_CTRL;
+static const int EVP_F_EVP_CIPHER_CTX_SET_KEY_LENGTH;
+static const int EVP_F_EVP_CIPHERINIT_EX;
 static const int EVP_F_EVP_DECRYPTFINAL_EX;
+static const int EVP_F_EVP_DIGESTINIT_EX;
 static const int EVP_F_EVP_ENCRYPTFINAL_EX;
-
+static const int EVP_F_EVP_MD_CTX_COPY_EX;
+static const int EVP_F_EVP_OPENINIT;
+static const int EVP_F_EVP_PBE_ALG_ADD;
+static const int EVP_F_EVP_PBE_CIPHERINIT;
+static const int EVP_F_EVP_PKCS82PKEY;
+static const int EVP_F_EVP_PKEY2PKCS8_BROKEN;
+static const int EVP_F_EVP_PKEY_COPY_PARAMETERS;
+static const int EVP_F_EVP_PKEY_DECRYPT;
+static const int EVP_F_EVP_PKEY_ENCRYPT;
+static const int EVP_F_EVP_PKEY_GET1_DH;
+static const int EVP_F_EVP_PKEY_GET1_DSA;
+static const int EVP_F_EVP_PKEY_GET1_ECDSA;
+static const int EVP_F_EVP_PKEY_GET1_EC_KEY;
+static const int EVP_F_EVP_PKEY_GET1_RSA;
+static const int EVP_F_EVP_PKEY_NEW;
+static const int EVP_F_EVP_RIJNDAEL;
+static const int EVP_F_EVP_SIGNFINAL;
+static const int EVP_F_EVP_VERIFYFINAL;
+static const int EVP_F_PKCS5_PBE_KEYIVGEN;
+static const int EVP_F_PKCS5_V2_PBE_KEYIVGEN;
+static const int EVP_F_PKCS8_SET_BROKEN;
+static const int EVP_F_RC2_MAGIC_TO_METH;
+static const int EVP_F_RC5_CTRL;
+static const int EVP_R_AES_KEY_SETUP_FAILED;
+static const int EVP_R_ASN1_LIB;
+static const int EVP_R_BAD_BLOCK_LENGTH;
+static const int EVP_R_BAD_KEY_LENGTH;
+static const int EVP_R_BN_DECODE_ERROR;
+static const int EVP_R_BN_PUBKEY_ERROR;
+static const int EVP_R_CAMELLIA_KEY_SETUP_FAILED;
+static const int EVP_R_CIPHER_PARAMETER_ERROR;
+static const int EVP_R_CTRL_NOT_IMPLEMENTED;
+static const int EVP_R_CTRL_OPERATION_NOT_IMPLEMENTED;
 static const int EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH;
+static const int EVP_R_DECODE_ERROR;
+static const int EVP_R_DIFFERENT_KEY_TYPES;
+static const int EVP_R_DISABLED_FOR_FIPS;
+static const int EVP_R_ENCODE_ERROR;
+static const int EVP_R_INITIALIZATION_ERROR;
+static const int EVP_R_INPUT_NOT_INITIALIZED;
+static const int EVP_R_INVALID_KEY_LENGTH;
+static const int EVP_R_IV_TOO_LARGE;
+static const int EVP_R_KEYGEN_FAILURE;
+static const int EVP_R_MISSING_PARAMETERS;
+static const int EVP_R_NO_CIPHER_SET;
+static const int EVP_R_NO_DIGEST_SET;
+static const int EVP_R_NO_DSA_PARAMETERS;
+static const int EVP_R_NO_SIGN_FUNCTION_CONFIGURED;
+static const int EVP_R_NO_VERIFY_FUNCTION_CONFIGURED;
+static const int EVP_R_PKCS8_UNKNOWN_BROKEN_TYPE;
+static const int EVP_R_PUBLIC_KEY_NOT_RSA;
+static const int EVP_R_UNKNOWN_PBE_ALGORITHM;
+static const int EVP_R_UNSUPORTED_NUMBER_OF_ROUNDS;
+static const int EVP_R_UNSUPPORTED_CIPHER;
+static const int EVP_R_UNSUPPORTED_KEY_DERIVATION_FUNCTION;
+static const int EVP_R_UNSUPPORTED_KEYLENGTH;
+static const int EVP_R_UNSUPPORTED_SALT_TYPE;
+static const int EVP_R_WRONG_FINAL_BLOCK_LENGTH;
+static const int EVP_R_WRONG_PUBLIC_KEY_TYPE;
 
 static const int PEM_F_D2I_PKCS8PRIVATEKEY_BIO;
-static const int PEM_F_D2I_PKCS8PRIVATEKEY_BIO;
 static const int PEM_F_D2I_PKCS8PRIVATEKEY_FP;
 static const int PEM_F_DO_PK8PKEY;
 static const int PEM_F_DO_PK8PKEY_FP;
@@ -50,7 +192,6 @@
 static const int PEM_F_PEM_READ;
 static const int PEM_F_PEM_READ_BIO;
 static const int PEM_F_PEM_READ_BIO_PRIVATEKEY;
-static const int PEM_F_PEM_READ_BIO_PRIVATEKEY;
 static const int PEM_F_PEM_READ_PRIVATEKEY;
 static const int PEM_F_PEM_SEALFINAL;
 static const int PEM_F_PEM_SEALINIT;
@@ -66,12 +207,11 @@
 static const int PEM_R_BAD_END_LINE;
 static const int PEM_R_BAD_IV_CHARS;
 static const int PEM_R_BAD_PASSWORD_READ;
-static const int PEM_R_BAD_PASSWORD_READ;
 static const int PEM_R_ERROR_CONVERTING_PRIVATE_KEY;
+static const int PEM_R_NO_START_LINE;
 static const int PEM_R_NOT_DEK_INFO;
 static const int PEM_R_NOT_ENCRYPTED;
 static const int PEM_R_NOT_PROC_TYPE;
-static const int PEM_R_NO_START_LINE;
 static const int PEM_R_PROBLEMS_GETTING_PASSWORD;
 static const int PEM_R_PUBLIC_KEY_NO_RSA;
 static const int PEM_R_READ_KEY;
@@ -114,9 +254,24 @@
 int ERR_GET_FUNC(unsigned long);
 int ERR_GET_REASON(unsigned long);
 int ERR_FATAL_ERROR(unsigned long);
+/* introduced in 1.0.0 so we have to handle this specially to continue
+ * supporting 0.9.8
+ */
+void ERR_remove_thread_state(const CRYPTO_THREADID *);
 """
 
 CUSTOMIZATIONS = """
+#if OPENSSL_VERSION_NUMBER >= 0x10000000L
+static const long Cryptography_HAS_REMOVE_THREAD_STATE = 1;
+#else
+static const long Cryptography_HAS_REMOVE_THREAD_STATE = 0;
+typedef uint32_t CRYPTO_THREADID;
+void (*ERR_remove_thread_state)(const CRYPTO_THREADID *);
+#endif
 """
 
-CONDITIONAL_NAMES = {}
+CONDITIONAL_NAMES = {
+    "Cryptography_HAS_REMOVE_THREAD_STATE": [
+        "ERR_remove_thread_state"
+    ],
+}
diff --git a/cryptography/hazmat/bindings/openssl/pem.py b/cryptography/hazmat/bindings/openssl/pem.py
index ee5552c..8b717c2 100644
--- a/cryptography/hazmat/bindings/openssl/pem.py
+++ b/cryptography/hazmat/bindings/openssl/pem.py
@@ -27,7 +27,7 @@
                              unsigned char *, int, pem_password_cb *, void *);
 
 EVP_PKEY *PEM_read_bio_PrivateKey(BIO *, EVP_PKEY **, pem_password_cb *,
-                                  void *);
+                                 void *);
 
 int PEM_write_bio_PKCS8PrivateKey(BIO *, EVP_PKEY *, const EVP_CIPHER *,
                                   char *, int, pem_password_cb *, void *);
@@ -48,6 +48,29 @@
 
 PKCS7 *PEM_read_bio_PKCS7(BIO *, PKCS7 **, pem_password_cb *, void *);
 DH *PEM_read_bio_DHparams(BIO *, DH **, pem_password_cb *, void *);
+
+DSA *PEM_read_bio_DSAPrivateKey(BIO *, DSA **, pem_password_cb *, void *);
+
+RSA *PEM_read_bio_RSAPrivateKey(BIO *, RSA **, pem_password_cb *, void *);
+
+int PEM_write_bio_DSAPrivateKey(BIO *, DSA *, const EVP_CIPHER *,
+                                unsigned char *, int,
+                                pem_password_cb *, void *);
+
+int PEM_write_bio_RSAPrivateKey(BIO *, RSA *, const EVP_CIPHER *,
+                                unsigned char *, int,
+                                pem_password_cb *, void *);
+
+DSA *PEM_read_bio_DSA_PUBKEY(BIO *, DSA **, pem_password_cb *, void *);
+
+RSA *PEM_read_bio_RSAPublicKey(BIO *, RSA **, pem_password_cb *, void *);
+
+int PEM_write_bio_DSA_PUBKEY(BIO *, DSA *);
+
+int PEM_write_bio_RSAPublicKey(BIO *, const RSA *);
+
+EVP_PKEY *PEM_read_bio_PUBKEY(BIO *, EVP_PKEY **, pem_password_cb *, void *);
+int PEM_write_bio_PUBKEY(BIO *, EVP_PKEY *);
 """
 
 MACROS = """
diff --git a/cryptography/hazmat/bindings/openssl/ssl.py b/cryptography/hazmat/bindings/openssl/ssl.py
index d0d5ae2..cd872d1 100644
--- a/cryptography/hazmat/bindings/openssl/ssl.py
+++ b/cryptography/hazmat/bindings/openssl/ssl.py
@@ -77,6 +77,7 @@
 static const int SSL_OP_COOKIE_EXCHANGE;
 static const int SSL_OP_NO_TICKET;
 static const int SSL_OP_ALL;
+static const int SSL_OP_SINGLE_ECDH_USE;
 static const int SSL_VERIFY_PEER;
 static const int SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
 static const int SSL_VERIFY_CLIENT_ONCE;
@@ -231,6 +232,7 @@
 long SSL_CTX_set_session_cache_mode(SSL_CTX *, long);
 long SSL_CTX_get_session_cache_mode(SSL_CTX *);
 long SSL_CTX_set_tmp_dh(SSL_CTX *, DH *);
+long SSL_CTX_set_tmp_ecdh(SSL_CTX *, EC_KEY *);
 long SSL_CTX_add_extra_chain_cert(SSL_CTX *, X509 *);
 
 /*- These aren't macros these functions are all const X on openssl > 1.0.x -*/
@@ -345,6 +347,10 @@
 static const long Cryptography_HAS_SSL_OP_MSIE_SSLV2_RSA_PADDING = 0;
 const long SSL_OP_MSIE_SSLV2_RSA_PADDING = 0;
 #endif
+
+#ifdef OPENSSL_NO_EC
+long (*SSL_CTX_set_tmp_ecdh)(SSL_CTX *, EC_KEY *) = NULL;
+#endif
 """
 
 CONDITIONAL_NAMES = {
@@ -385,4 +391,8 @@
     "Cryptography_HAS_SSL_OP_MSIE_SSLV2_RSA_PADDING": [
         "SSL_OP_MSIE_SSLV2_RSA_PADDING",
     ],
+
+    "Cryptography_HAS_EC": [
+        "EC_KEY_new_by_curve_name",
+    ]
 }
diff --git a/cryptography/hazmat/bindings/utils.py b/cryptography/hazmat/bindings/utils.py
index 69290eb..b825348 100644
--- a/cryptography/hazmat/bindings/utils.py
+++ b/cryptography/hazmat/bindings/utils.py
@@ -34,6 +34,7 @@
         condition.
     """
     ffi = cffi.FFI()
+    types = []
     includes = []
     functions = []
     macros = []
@@ -43,20 +44,13 @@
         __import__(module_name)
         module = sys.modules[module_name]
 
-        ffi.cdef(module.TYPES)
-
+        types.append(module.TYPES)
         macros.append(module.MACROS)
         functions.append(module.FUNCTIONS)
         includes.append(module.INCLUDES)
         customizations.append(module.CUSTOMIZATIONS)
 
-    # loop over the functions & macros after declaring all the types
-    # so we can set interdependent types in different files and still
-    # have them all defined before we parse the funcs & macros
-    for func in functions:
-        ffi.cdef(func)
-    for macro in macros:
-        ffi.cdef(macro)
+    ffi.cdef("\n".join(types + functions + macros))
 
     # We include functions here so that if we got any of their definitions
     # wrong, the underlying C compiler will explode. In C you are allowed
diff --git a/dev-requirements.txt b/dev-requirements.txt
index b2a6c79..70a2b9b 100644
--- a/dev-requirements.txt
+++ b/dev-requirements.txt
@@ -5,6 +5,7 @@
 pretend
 pytest
 sphinx
+sphinxcontrib-spelling
 sphinx_rtd_theme
 tox
 twine
diff --git a/docs/changelog.rst b/docs/changelog.rst
index 41db635..289992f 100644
--- a/docs/changelog.rst
+++ b/docs/changelog.rst
@@ -1,9 +1,12 @@
 Changelog
 =========
+
 0.2 - 2014-XX-XX
 ~~~~~~~~~~~~~~~~
 
-* In development.
+**In development**
+
+* Added initial CommonCrypto bindings.
 
 0.1 - 2014-01-08
 ~~~~~~~~~~~~~~~~
diff --git a/docs/conf.py b/docs/conf.py
index a42dcb2..3486fb3 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -19,6 +19,11 @@
 except ImportError:
     sphinx_rtd_theme = None
 
+try:
+    from sphinxcontrib import spelling
+except ImportError:
+    spelling = None
+
 
 # If extensions (or modules to document with autodoc) are in another directory,
 # add these directories to sys.path here. If the directory is relative to the
@@ -38,9 +43,11 @@
     'sphinx.ext.intersphinx',
     'sphinx.ext.viewcode',
     'cryptography-docs',
-    'sphinxcontrib.spelling',
 ]
 
+if spelling is not None:
+    extensions.append('sphinxcontrib.spelling')
+
 # Add any paths that contain templates here, relative to this directory.
 templates_path = ['_templates']
 
@@ -263,3 +270,5 @@
 
 # Example configuration for intersphinx: refer to the Python standard library.
 intersphinx_mapping = {'http://docs.python.org/': None}
+
+epub_theme = 'epub'
diff --git a/docs/hazmat/bindings/commoncrypto.rst b/docs/hazmat/bindings/commoncrypto.rst
index 25535e0..c4f614c 100644
--- a/docs/hazmat/bindings/commoncrypto.rst
+++ b/docs/hazmat/bindings/commoncrypto.rst
@@ -5,6 +5,8 @@
 
 .. currentmodule:: cryptography.hazmat.bindings.commoncrypto.binding
 
+.. versionadded:: 0.2
+
 These are `CFFI`_ bindings to the `CommonCrypto`_ C library. It is available on
 Mac OS X.
 
diff --git a/docs/hazmat/primitives/symmetric-encryption.rst b/docs/hazmat/primitives/symmetric-encryption.rst
index 8316569..7d95404 100644
--- a/docs/hazmat/primitives/symmetric-encryption.rst
+++ b/docs/hazmat/primitives/symmetric-encryption.rst
@@ -324,6 +324,11 @@
             return (iv, ciphertext, encryptor.tag)
 
         def decrypt(key, associated_data, iv, ciphertext, tag):
+            if len(tag) != 16:
+                raise ValueError(
+                    "tag must be 16 bytes -- truncation not supported"
+                )
+
             # Construct a Cipher object, with the key, iv, and additionally the
             # GCM tag used for authenticating the message.
             decryptor = Cipher(