Tweaks for node.js

node.js is, effectively, another bindings library. However, it's better
written than most and, with these changes, only a couple of tiny fixes
are needed in node.js. Some of these changes are a little depressing
however so we'll need to push node.js to use APIs where possible.

Changes:
  ∙ Support verify_recover. This is very obscure and the motivation
    appears to be https://github.com/nodejs/node/issues/477 – where it's
    not clear that anyone understands what it means :(
  ∙ Add a few, no-op #defines
  ∙ Add some members to |SSL_CTX| and |SSL| – node.js needs to not
    reach into these structs in the future.
  ∙ Add EC_get_builtin_curves.
  ∙ Add EVP_[CIPHER|MD]_do_all_sorted – these functions are limited to
    decrepit.

Change-Id: I9a3566054260d6c4db9d430beb7c46cc970a9d46
Reviewed-on: https://boringssl-review.googlesource.com/6952
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/crypto/ec/ec.c b/crypto/ec/ec.c
index 2f8d2b1..ca3ce37 100644
--- a/crypto/ec/ec.c
+++ b/crypto/ec/ec.c
@@ -883,3 +883,21 @@
     abort();
   }
 }
+
+size_t EC_get_builtin_curves(EC_builtin_curve *out_curves,
+                             size_t max_num_curves) {
+  unsigned num_built_in_curves;
+  for (num_built_in_curves = 0;; num_built_in_curves++) {
+    if (OPENSSL_built_in_curves[num_built_in_curves].nid == NID_undef) {
+      break;
+    }
+  }
+
+  unsigned i;
+  for (i = 0; i < max_num_curves && i < num_built_in_curves; i++) {
+    out_curves[i].comment = OPENSSL_built_in_curves[i].data->comment;
+    out_curves[i].nid = OPENSSL_built_in_curves[i].nid;
+  }
+
+  return num_built_in_curves;
+}
diff --git a/crypto/evp/evp_ctx.c b/crypto/evp/evp_ctx.c
index 9e038cd..69d556a 100644
--- a/crypto/evp/evp_ctx.c
+++ b/crypto/evp/evp_ctx.c
@@ -342,6 +342,35 @@
   return ctx->pmeth->decrypt(ctx, out, outlen, in, inlen);
 }
 
+int EVP_PKEY_verify_recover_init(EVP_PKEY_CTX *ctx) {
+  if (!ctx || !ctx->pmeth || !ctx->pmeth->verify_recover) {
+    OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+    return 0;
+  }
+  ctx->operation = EVP_PKEY_OP_VERIFYRECOVER;
+  if (!ctx->pmeth->verify_recover_init) {
+    return 1;
+  }
+  if (!ctx->pmeth->verify_recover_init(ctx)) {
+    ctx->operation = EVP_PKEY_OP_UNDEFINED;
+    return 0;
+  }
+  return 1;
+}
+
+int EVP_PKEY_verify_recover(EVP_PKEY_CTX *ctx, uint8_t *out, size_t *out_len,
+                            const uint8_t *sig, size_t sig_len) {
+  if (!ctx || !ctx->pmeth || !ctx->pmeth->verify_recover) {
+    OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+    return 0;
+  }
+  if (ctx->operation != EVP_PKEY_OP_VERIFYRECOVER) {
+    OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATON_NOT_INITIALIZED);
+    return 0;
+  }
+  return ctx->pmeth->verify_recover(ctx, out, out_len, sig, sig_len);
+}
+
 int EVP_PKEY_derive_init(EVP_PKEY_CTX *ctx) {
   if (!ctx || !ctx->pmeth || !ctx->pmeth->derive) {
     OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
diff --git a/crypto/evp/evp_extra_test.cc b/crypto/evp/evp_extra_test.cc
index 21e5da7..00858f7 100644
--- a/crypto/evp/evp_extra_test.cc
+++ b/crypto/evp/evp_extra_test.cc
@@ -15,6 +15,7 @@
 #include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 
 #include <utility>
 #include <vector>
@@ -658,6 +659,84 @@
   return true;
 }
 
+static bool TestVerifyRecover() {
+  ScopedEVP_PKEY pkey = LoadExampleRSAKey();
+  if (!pkey) {
+    return false;
+  }
+
+  ScopedRSA rsa(EVP_PKEY_get1_RSA(pkey.get()));
+  if (!rsa) {
+    return false;
+  }
+
+  const uint8_t kDummyHash[32] = {0};
+  uint8_t sig[2048/8];
+  unsigned sig_len = sizeof(sig);
+
+  if (!RSA_sign(NID_sha256, kDummyHash, sizeof(kDummyHash), sig, &sig_len,
+                rsa.get())) {
+    fprintf(stderr, "RSA_sign failed.\n");
+    ERR_print_errors_fp(stderr);
+    return false;
+  }
+
+  size_t out_len;
+  ScopedEVP_PKEY_CTX ctx(EVP_PKEY_CTX_new(pkey.get(), nullptr));
+  if (!EVP_PKEY_verify_recover_init(ctx.get()) ||
+      !EVP_PKEY_CTX_set_rsa_padding(ctx.get(), RSA_PKCS1_PADDING) ||
+      !EVP_PKEY_CTX_set_signature_md(ctx.get(), EVP_sha256()) ||
+      !EVP_PKEY_verify_recover(ctx.get(), nullptr, &out_len, sig, sig_len)) {
+    fprintf(stderr, "verify_recover failed will nullptr buffer.\n");
+    ERR_print_errors_fp(stderr);
+    return false;
+  }
+
+  std::vector<uint8_t> recovered;
+  recovered.resize(out_len);
+
+  if (!EVP_PKEY_verify_recover(ctx.get(), recovered.data(), &out_len, sig,
+                               sig_len)) {
+    fprintf(stderr, "verify_recover failed.\n");
+    ERR_print_errors_fp(stderr);
+    return false;
+  }
+
+  if (out_len != sizeof(kDummyHash)) {
+    fprintf(stderr, "verify_recover length is %u, expected %u.\n",
+            static_cast<unsigned>(out_len),
+            static_cast<unsigned>(sizeof(kDummyHash)));
+    return false;
+  }
+
+  if (memcmp(recovered.data(), kDummyHash, sizeof(kDummyHash)) != 0) {
+    fprintf(stderr, "verify_recover got wrong value.\n");
+    ERR_print_errors_fp(stderr);
+    return false;
+  }
+
+  out_len = recovered.size();
+  if (!EVP_PKEY_CTX_set_signature_md(ctx.get(), nullptr) ||
+      !EVP_PKEY_verify_recover(ctx.get(), recovered.data(), &out_len, sig,
+                               sig_len)) {
+    fprintf(stderr, "verify_recover failed with NULL MD.\n");
+    ERR_print_errors_fp(stderr);
+    return false;
+  }
+
+  /* The size of a SHA-256 hash plus PKCS#1 v1.5 ASN.1 stuff happens to be 51
+   * bytes. */
+  static const size_t kExpectedASN1Size = 51;
+  if (out_len != kExpectedASN1Size) {
+    fprintf(stderr, "verify_recover length without MD is %u, expected %u.\n",
+            static_cast<unsigned>(out_len),
+            static_cast<unsigned>(kExpectedASN1Size));
+    return false;
+  }
+
+  return true;
+}
+
 static bool TestBadPSSParameters(void) {
   CBS in, tbs_cert, signature;
   ScopedEVP_PKEY pkey;
@@ -835,6 +914,12 @@
     return 1;
   }
 
+  if (!TestVerifyRecover()) {
+    fprintf(stderr, "EVP_PKEY_verify_recover failed\n");
+    ERR_print_errors_fp(stderr);
+    return 1;
+  }
+
   if (!TestBadPSSParameters()) {
     fprintf(stderr, "TestBadPSSParameters failed\n");
     ERR_print_errors_fp(stderr);
diff --git a/crypto/evp/internal.h b/crypto/evp/internal.h
index aa52d53..06788b8 100644
--- a/crypto/evp/internal.h
+++ b/crypto/evp/internal.h
@@ -249,6 +249,10 @@
   int (*verify)(EVP_PKEY_CTX *ctx, const uint8_t *sig, size_t siglen,
                 const uint8_t *tbs, size_t tbslen);
 
+  int (*verify_recover_init)(EVP_PKEY_CTX *ctx);
+  int (*verify_recover)(EVP_PKEY_CTX *ctx, uint8_t *out, size_t *out_len,
+                        const uint8_t *sig, size_t sig_len);
+
   int (*encrypt_init)(EVP_PKEY_CTX *ctx);
   int (*encrypt)(EVP_PKEY_CTX *ctx, uint8_t *out, size_t *outlen,
                  const uint8_t *in, size_t inlen);
diff --git a/crypto/evp/p_ec.c b/crypto/evp/p_ec.c
index 77f213d..f4c6f32 100644
--- a/crypto/evp/p_ec.c
+++ b/crypto/evp/p_ec.c
@@ -273,11 +273,26 @@
 }
 
 const EVP_PKEY_METHOD ec_pkey_meth = {
-    EVP_PKEY_EC,          0 /* flags */,        pkey_ec_init,
-    pkey_ec_copy,         pkey_ec_cleanup,      0 /* paramgen_init */,
-    pkey_ec_paramgen,     0 /* keygen_init */,  pkey_ec_keygen,
-    0 /* sign_init */,    pkey_ec_sign,         0 /* verify_init */,
-    pkey_ec_verify,       0 /* encrypt_init */, 0 /* encrypt */,
-    0 /* decrypt_init */, 0 /* decrypt */,      0 /* derive_init */,
-    pkey_ec_derive,       pkey_ec_ctrl,
+    EVP_PKEY_EC,
+    0 /* flags */,
+    pkey_ec_init,
+    pkey_ec_copy,
+    pkey_ec_cleanup,
+    0 /* paramgen_init */,
+    pkey_ec_paramgen,
+    0 /* keygen_init */,
+    pkey_ec_keygen,
+    0 /* sign_init */,
+    pkey_ec_sign,
+    0 /* verify_init */,
+    pkey_ec_verify,
+    0 /* verify_recover_init */,
+    0 /* verify_recover */,
+    0 /* encrypt_init */,
+    0 /* encrypt */,
+    0 /* decrypt_init */,
+    0 /* decrypt */,
+    0 /* derive_init */,
+    pkey_ec_derive,
+    pkey_ec_ctrl,
 };
diff --git a/crypto/evp/p_rsa.c b/crypto/evp/p_rsa.c
index 895d351..5f6db76 100644
--- a/crypto/evp/p_rsa.c
+++ b/crypto/evp/p_rsa.c
@@ -256,6 +256,81 @@
   return 1;
 }
 
+static int pkey_rsa_verify_recover(EVP_PKEY_CTX *ctx, uint8_t *out,
+                                   size_t *out_len, const uint8_t *sig,
+                                   size_t sig_len) {
+  RSA_PKEY_CTX *rctx = ctx->data;
+  RSA *rsa = ctx->pkey->pkey.rsa;
+  const size_t key_len = EVP_PKEY_size(ctx->pkey);
+
+  if (out == NULL) {
+    *out_len = key_len;
+    return 1;
+  }
+
+  if (*out_len < key_len) {
+    OPENSSL_PUT_ERROR(EVP, EVP_R_BUFFER_TOO_SMALL);
+    return 0;
+  }
+
+  if (!setup_tbuf(rctx, ctx)) {
+    return 0;
+  }
+
+  if (rctx->md == NULL) {
+    const size_t ret = RSA_public_decrypt(sig_len, sig, rctx->tbuf,
+                                          ctx->pkey->pkey.rsa, rctx->pad_mode);
+    if (ret < 0) {
+      return 0;
+    }
+    *out_len = ret;
+    memcpy(out, rctx->tbuf, *out_len);
+    return 1;
+  }
+
+  if (rctx->pad_mode != RSA_PKCS1_PADDING) {
+    return 0;
+  }
+
+  uint8_t *asn1_prefix;
+  size_t asn1_prefix_len;
+  int asn1_prefix_allocated;
+  if (!RSA_add_pkcs1_prefix(&asn1_prefix, &asn1_prefix_len,
+                            &asn1_prefix_allocated, EVP_MD_type(rctx->md), NULL,
+                            0)) {
+    return 0;
+  }
+
+  size_t rslen;
+  int ok = 1;
+  if (!RSA_verify_raw(rsa, &rslen, rctx->tbuf, key_len, sig, sig_len,
+                      RSA_PKCS1_PADDING) ||
+      rslen < asn1_prefix_len ||
+      CRYPTO_memcmp(rctx->tbuf, asn1_prefix, asn1_prefix_len) != 0) {
+    ok = 0;
+  }
+
+  if (asn1_prefix_allocated) {
+    OPENSSL_free(asn1_prefix);
+  }
+
+  if (!ok) {
+    return 0;
+  }
+
+  const size_t result_len = rslen - asn1_prefix_len;
+  if (result_len != EVP_MD_size(rctx->md)) {
+    return 0;
+  }
+
+  if (out != NULL) {
+    memcpy(out, rctx->tbuf + asn1_prefix_len, result_len);
+  }
+  *out_len = result_len;
+
+  return 1;
+}
+
 static int pkey_rsa_encrypt(EVP_PKEY_CTX *ctx, uint8_t *out, size_t *outlen,
                             const uint8_t *in, size_t inlen) {
   RSA_PKEY_CTX *rctx = ctx->data;
@@ -503,13 +578,28 @@
 }
 
 const EVP_PKEY_METHOD rsa_pkey_meth = {
-    EVP_PKEY_RSA,         0 /* flags */,        pkey_rsa_init,
-    pkey_rsa_copy,        pkey_rsa_cleanup,     0 /* paramgen_init */,
-    0 /* paramgen */,     0 /* keygen_init */,  pkey_rsa_keygen,
-    0 /* sign_init */,    pkey_rsa_sign,        0 /* verify_init */,
-    pkey_rsa_verify,      0 /* encrypt_init */, pkey_rsa_encrypt,
-    0 /* decrypt_init */, pkey_rsa_decrypt,     0 /* derive_init */,
-    0 /* derive */,       pkey_rsa_ctrl,
+    EVP_PKEY_RSA,
+    0 /* flags */,
+    pkey_rsa_init,
+    pkey_rsa_copy,
+    pkey_rsa_cleanup,
+    0 /* paramgen_init */,
+    0 /* paramgen */,
+    0 /* keygen_init */,
+    pkey_rsa_keygen,
+    0 /* sign_init */,
+    pkey_rsa_sign,
+    0 /* verify_init */,
+    pkey_rsa_verify,
+    0 /* verify_recover_init */,
+    pkey_rsa_verify_recover,
+    0 /* encrypt_init */,
+    pkey_rsa_encrypt,
+    0 /* decrypt_init */,
+    pkey_rsa_decrypt,
+    0 /* derive_init */,
+    0 /* derive */,
+    pkey_rsa_ctrl,
 };
 
 int EVP_PKEY_CTX_set_rsa_padding(EVP_PKEY_CTX *ctx, int padding) {
diff --git a/decrepit/CMakeLists.txt b/decrepit/CMakeLists.txt
index 0773f9a..a7677d0 100644
--- a/decrepit/CMakeLists.txt
+++ b/decrepit/CMakeLists.txt
@@ -2,6 +2,7 @@
 add_subdirectory(blowfish)
 add_subdirectory(cast)
 add_subdirectory(des)
+add_subdirectory(evp)
 add_subdirectory(rsa)
 add_subdirectory(xts)
 
@@ -12,6 +13,7 @@
   $<TARGET_OBJECTS:blowfish>
   $<TARGET_OBJECTS:cast>
   $<TARGET_OBJECTS:des_decrepit>
+  $<TARGET_OBJECTS:evp_decrepit>
   $<TARGET_OBJECTS:rsa_decrepit>
   $<TARGET_OBJECTS:xts>
 )
diff --git a/decrepit/evp/CMakeLists.txt b/decrepit/evp/CMakeLists.txt
new file mode 100644
index 0000000..ee3bf33
--- /dev/null
+++ b/decrepit/evp/CMakeLists.txt
@@ -0,0 +1,9 @@
+include_directories(../../include)
+
+add_library(
+  evp_decrepit
+
+  OBJECT
+
+  evp_do_all.c
+)
diff --git a/decrepit/evp/evp_do_all.c b/decrepit/evp/evp_do_all.c
new file mode 100644
index 0000000..621c0b1
--- /dev/null
+++ b/decrepit/evp/evp_do_all.c
@@ -0,0 +1,77 @@
+/* Copyright (c) 2016, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#include <openssl/evp.h>
+
+
+void EVP_CIPHER_do_all_sorted(void (*callback)(const EVP_CIPHER *cipher,
+                                               const char *name,
+                                               const char *unused, void *arg),
+                              void *arg) {
+  callback(EVP_aes_128_cbc(), "AES-128-CBC", NULL, arg);
+  callback(EVP_aes_128_ctr(), "AES-128-CTR", NULL, arg);
+  callback(EVP_aes_128_ecb(), "AES-128-ECB", NULL, arg);
+  callback(EVP_aes_128_ofb(), "AES-128-OFB", NULL, arg);
+  callback(EVP_aes_256_cbc(), "AES-256-CBC", NULL, arg);
+  callback(EVP_aes_256_ctr(), "AES-256-CTR", NULL, arg);
+  callback(EVP_aes_256_ecb(), "AES-256-ECB", NULL, arg);
+  callback(EVP_aes_256_ofb(), "AES-256-OFB", NULL, arg);
+  callback(EVP_aes_256_xts(), "AES-256-XTS", NULL, arg);
+  callback(EVP_des_cbc(), "DES-CBC", NULL, arg);
+  callback(EVP_des_ecb(), "DES-ECB", NULL, arg);
+  callback(EVP_des_ede(), "DES-EDE", NULL, arg);
+  callback(EVP_des_ede_cbc(), "DES-EDE-CBC", NULL, arg);
+  callback(EVP_des_ede3_cbc(), "DES-EDE3-CBC", NULL, arg);
+  callback(EVP_rc2_cbc(), "RC2-CBC", NULL, arg);
+  callback(EVP_rc4(), "RC4", NULL, arg);
+
+  /* OpenSSL returns everything twice, the second time in lower case. */
+  callback(EVP_aes_128_cbc(), "aes-128-cbc", NULL, arg);
+  callback(EVP_aes_128_ctr(), "aes-128-ctr", NULL, arg);
+  callback(EVP_aes_128_ecb(), "aes-128-ecb", NULL, arg);
+  callback(EVP_aes_128_ofb(), "aes-128-ofb", NULL, arg);
+  callback(EVP_aes_256_cbc(), "aes-256-cbc", NULL, arg);
+  callback(EVP_aes_256_ctr(), "aes-256-ctr", NULL, arg);
+  callback(EVP_aes_256_ecb(), "aes-256-ecb", NULL, arg);
+  callback(EVP_aes_256_ofb(), "aes-256-ofb", NULL, arg);
+  callback(EVP_aes_256_xts(), "aes-256-xts", NULL, arg);
+  callback(EVP_des_cbc(), "des-cbc", NULL, arg);
+  callback(EVP_des_ecb(), "des-ecb", NULL, arg);
+  callback(EVP_des_ede(), "des-ede", NULL, arg);
+  callback(EVP_des_ede_cbc(), "des-ede-cbc", NULL, arg);
+  callback(EVP_des_ede3_cbc(), "des-ede3-cbc", NULL, arg);
+  callback(EVP_rc2_cbc(), "rc2-cbc", NULL, arg);
+  callback(EVP_rc4(), "rc4", NULL, arg);
+}
+
+void EVP_MD_do_all_sorted(void (*callback)(const EVP_MD *cipher,
+                                           const char *name, const char *unused,
+                                           void *arg),
+                          void *arg) {
+  callback(EVP_md4(), "MD4", NULL, arg);
+  callback(EVP_md5(), "MD5", NULL, arg);
+  callback(EVP_sha1(), "SHA1", NULL, arg);
+  callback(EVP_sha224(), "SHA224", NULL, arg);
+  callback(EVP_sha256(), "SHA256", NULL, arg);
+  callback(EVP_sha384(), "SHA384", NULL, arg);
+  callback(EVP_sha512(), "SHA512", NULL, arg);
+
+  callback(EVP_md4(), "md4", NULL, arg);
+  callback(EVP_md5(), "md5", NULL, arg);
+  callback(EVP_sha1(), "sha1", NULL, arg);
+  callback(EVP_sha224(), "sha224", NULL, arg);
+  callback(EVP_sha256(), "sha256", NULL, arg);
+  callback(EVP_sha384(), "sha384", NULL, arg);
+  callback(EVP_sha512(), "sha512", NULL, arg);
+}
diff --git a/include/openssl/bio.h b/include/openssl/bio.h
index 3447f5b..6ca3575 100644
--- a/include/openssl/bio.h
+++ b/include/openssl/bio.h
@@ -711,6 +711,11 @@
 #define BIO_CTRL_GET_CALLBACK	15  /* opt - set callback function */
 #define BIO_CTRL_SET_FILENAME	30	/* BIO_s_file special */
 
+/* These are never used, but exist to allow code to compile more easily. */
+#define BIO_CTRL_DUP	100
+#define BIO_CTRL_PUSH	101
+#define BIO_CTRL_POP	102
+
 
 /* Android compatibility section.
  *
diff --git a/include/openssl/crypto.h b/include/openssl/crypto.h
index 193c8c3..29d5892 100644
--- a/include/openssl/crypto.h
+++ b/include/openssl/crypto.h
@@ -42,7 +42,9 @@
 
 /* Deprecated functions. */
 
-#define OPENSSL_VERSION_TEXT "BoringSSL"
+/* OPENSSL_VERSION_TEXT contains a string the identifies the version of
+ * “OpenSSL”. node.js requires a version number in this text. */
+#define OPENSSL_VERSION_TEXT "OpenSSL 1.0.2 (compatible; BoringSSL)"
 
 #define SSLEAY_VERSION 0
 
diff --git a/include/openssl/ec.h b/include/openssl/ec.h
index 26f40b7..82f84ea 100644
--- a/include/openssl/ec.h
+++ b/include/openssl/ec.h
@@ -81,14 +81,24 @@
 typedef struct ec_group_st EC_GROUP;
 typedef struct ec_point_st EC_POINT;
 
-/** Enum for the point conversion form as defined in X9.62 (ECDSA)
- *  for the encoding of a elliptic curve point (x,y) */
+/* point_conversion_form_t enumerates forms, as defined in X9.62 (ECDSA), for
+ * the encoding of a elliptic curve point (x,y) */
 typedef enum {
-	/** the point is encoded as z||x, where the octet z specifies 
-	 *  which solution of the quadratic equation y is  */
-	POINT_CONVERSION_COMPRESSED = 2,
-	/** the point is encoded as z||x||y, where z is the octet 0x04  */
-	POINT_CONVERSION_UNCOMPRESSED = 4
+  /* POINT_CONVERSION_COMPRESSED indicates that the point is encoded as z||x,
+   * where the octet z specifies which solution of the quadratic equation y
+   * is. */
+  POINT_CONVERSION_COMPRESSED = 2,
+
+  /* POINT_CONVERSION_COMPRESSED indicates that the point is encoded as
+   * z||x||y, where z is the octet 0x04. */
+  POINT_CONVERSION_UNCOMPRESSED = 4,
+
+  /* POINT_CONVERSION_HYBRID indicates that the point is encoded as z||x||y,
+   * where z specifies which solution of the quadratic equation y is. This is
+   * not supported by the code and has never been observed in use.
+   *
+   * TODO(agl): remove once node.js no longer references this. */
+  POINT_CONVERSION_HYBRID = 6,
 } point_conversion_form_t;
 
 
@@ -306,6 +316,19 @@
 OPENSSL_EXPORT void EC_GROUP_set_point_conversion_form(
     EC_GROUP *group, point_conversion_form_t form);
 
+/* EC_builtin_curve describes a supported elliptic curve. */
+typedef struct {
+  int nid;
+  const char *comment;
+} EC_builtin_curve;
+
+/* EC_get_builtin_curves writes at most |max_num_curves| elements to
+ * |out_curves| and returns the total number that it would have written, had
+ * |max_num_curves| been large enough.
+ *
+ * The |EC_builtin_curve| items describe the supported elliptic curves. */
+OPENSSL_EXPORT size_t EC_get_builtin_curves(EC_builtin_curve *out_curves,
+                                            size_t max_num_curves);
 
 /* Old code expects to get EC_KEY from ec.h. */
 #include <openssl/ec_key.h>
diff --git a/include/openssl/evp.h b/include/openssl/evp.h
index 948353a..adf586e 100644
--- a/include/openssl/evp.h
+++ b/include/openssl/evp.h
@@ -511,6 +511,34 @@
                                     size_t *out_len, const uint8_t *in,
                                     size_t in_len);
 
+/* EVP_PKEY_verify_recover_init initialises an |EVP_PKEY_CTX| for a public-key
+ * decryption operation. It should be called before |EVP_PKEY_verify_recover|.
+ *
+ * Public-key decryption is a very obscure operation that is only implemented
+ * by RSA keys. It is effectively a signature verification operation that
+ * returns the signed message directly. It is almost certainly not what you
+ * want.
+ *
+ * It returns one on success or zero on error. */
+OPENSSL_EXPORT int EVP_PKEY_verify_recover_init(EVP_PKEY_CTX *ctx);
+
+/* EVP_PKEY_verify_recover decrypts |sig_len| bytes from |sig|. If |out| is
+ * NULL, the maximum size of the plaintext is written to |out_len|. Otherwise,
+ * |*out_len| must contain the number of bytes of space available at |out|. If
+ * sufficient, the ciphertext will be written to |out| and |*out_len| updated
+ * with the true length.
+ *
+ * WARNING: Setting |out| to NULL only gives the maximum size of the
+ * plaintext. The actual plaintext may be smaller.
+ *
+ * See the warning about this operation in |EVP_PKEY_verify_recover_init|. It
+ * is probably not what you want.
+ *
+ * It returns one on success or zero on error. */
+OPENSSL_EXPORT int EVP_PKEY_verify_recover(EVP_PKEY_CTX *ctx, uint8_t *out,
+                                           size_t *out_len, const uint8_t *sig,
+                                           size_t siglen);
+
 /* EVP_PKEY_derive_init initialises an |EVP_PKEY_CTX| for a key derivation
  * operation. It should be called before |EVP_PKEY_derive_set_peer| and
  * |EVP_PKEY_derive|.
@@ -659,6 +687,16 @@
 /* EVP_cleanup does nothing. */
 OPENSSL_EXPORT void EVP_cleanup(void);
 
+OPENSSL_EXPORT void EVP_CIPHER_do_all_sorted(
+    void (*callback)(const EVP_CIPHER *cipher, const char *name,
+                     const char *unused, void *arg),
+    void *arg);
+
+OPENSSL_EXPORT void EVP_MD_do_all_sorted(void (*callback)(const EVP_MD *cipher,
+                                                          const char *name,
+                                                          const char *unused,
+                                                          void *arg),
+                                         void *arg);
 
 /* Private functions */
 
diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
index 73fdbfe..f6ed6f4 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -2704,15 +2704,17 @@
 
 /* SSL_CTX_set_max_send_fragment sets the maximum length, in bytes, of records
  * sent by |ctx|. Beyond this length, handshake messages and application data
- * will be split into multiple records. */
-OPENSSL_EXPORT void SSL_CTX_set_max_send_fragment(SSL_CTX *ctx,
-                                                  size_t max_send_fragment);
+ * will be split into multiple records. It returns one on success or zero on
+ * error. */
+OPENSSL_EXPORT int SSL_CTX_set_max_send_fragment(SSL_CTX *ctx,
+                                                 size_t max_send_fragment);
 
-/* SSL_set_max_send_fragment sets the maximum length, in bytes, of records
- * sent by |ssl|. Beyond this length, handshake messages and application data
- * will be split into multiple records. */
-OPENSSL_EXPORT void SSL_set_max_send_fragment(SSL *ssl,
-                                              size_t max_send_fragment);
+/* SSL_set_max_send_fragment sets the maximum length, in bytes, of records sent
+ * by |ssl|. Beyond this length, handshake messages and application data will
+ * be split into multiple records. It returns one on success or zero on
+ * error. */
+OPENSSL_EXPORT int SSL_set_max_send_fragment(SSL *ssl,
+                                             size_t max_send_fragment);
 
 /* ssl_early_callback_ctx is passed to certain callbacks that are called very
  * early on during the server handshake. At this point, much of the SSL* hasn't
@@ -3732,6 +3734,11 @@
    * means that we'll accept Channel IDs from clients. For a client, means that
    * we'll advertise support. */
   unsigned tlsext_channel_id_enabled:1;
+
+  /* extra_certs is a dummy value included for compatibility.
+   * TODO(agl): remove once node.js no longer references this. */
+  STACK_OF(X509)* extra_certs;
+  int freelist_max_len;
 };
 
 struct ssl_st {
@@ -3914,6 +3921,9 @@
    * means that we'll accept Channel IDs from clients. For a client, means that
    * we'll advertise support. */
   unsigned tlsext_channel_id_enabled:1;
+
+  /* TODO(agl): remove once node.js not longer references this. */
+  int tlsext_status_type;
 };
 
 typedef struct ssl3_record_st {
@@ -4179,6 +4189,14 @@
 OPENSSL_EXPORT int SSL_set_ssl_method(SSL *s, const SSL_METHOD *method);
 
 
+/* Nodejs compatibility section (hidden).
+ *
+ * These defines exist for node.js, with the hope that we can eliminate the
+ * need for them over time. */
+#define SSLerr(function, reason) \
+  ERR_put_error(ERR_LIB_SSL, 0, reason, __FILE__, __LINE__)
+
+
 /* Preprocessor compatibility section (hidden).
  *
  * Historically, a number of APIs were implemented in OpenSSL as macros and
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
index 5946fc2..fe3c173 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -1180,7 +1180,7 @@
   ssl->max_cert_list = (uint32_t)max_cert_list;
 }
 
-void SSL_CTX_set_max_send_fragment(SSL_CTX *ctx, size_t max_send_fragment) {
+int SSL_CTX_set_max_send_fragment(SSL_CTX *ctx, size_t max_send_fragment) {
   if (max_send_fragment < 512) {
     max_send_fragment = 512;
   }
@@ -1188,9 +1188,11 @@
     max_send_fragment = SSL3_RT_MAX_PLAIN_LENGTH;
   }
   ctx->max_send_fragment = (uint16_t)max_send_fragment;
+
+  return 1;
 }
 
-void SSL_set_max_send_fragment(SSL *ssl, size_t max_send_fragment) {
+int SSL_set_max_send_fragment(SSL *ssl, size_t max_send_fragment) {
   if (max_send_fragment < 512) {
     max_send_fragment = 512;
   }
@@ -1198,6 +1200,8 @@
     max_send_fragment = SSL3_RT_MAX_PLAIN_LENGTH;
   }
   ssl->max_send_fragment = (uint16_t)max_send_fragment;
+
+  return 1;
 }
 
 int SSL_set_mtu(SSL *ssl, unsigned mtu) {
diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c
index 68c380a..346746a 100644
--- a/ssl/t1_lib.c
+++ b/ssl/t1_lib.c
@@ -1144,6 +1144,7 @@
 
 static void ext_ocsp_init(SSL *ssl) {
   ssl->s3->tmp.certificate_status_expected = 0;
+  ssl->tlsext_status_type = -1;
 }
 
 static int ext_ocsp_add_clienthello(SSL *ssl, CBB *out) {
@@ -1161,6 +1162,7 @@
     return 0;
   }
 
+  ssl->tlsext_status_type = TLSEXT_STATUSTYPE_ocsp;
   return 1;
 }