Inital import.

Initial fork from f2d678e6e89b6508147086610e985d4e8416e867 (1.0.2 beta).

(This change contains substantial changes from the original and
effectively starts a new history.)
diff --git a/crypto/evp/CMakeLists.txt b/crypto/evp/CMakeLists.txt
new file mode 100644
index 0000000..c3d8d8a
--- /dev/null
+++ b/crypto/evp/CMakeLists.txt
@@ -0,0 +1,30 @@
+include_directories(. .. ../../include)
+
+add_library(
+	evp
+
+	OBJECT
+
+	asn1.c
+	digestsign.c
+	evp.c
+	evp_ctx.c
+	evp_error.c
+	p_ec.c
+	p_ec_asn1.c
+	p_hmac.c
+	p_hmac_asn1.c
+	p_rsa.c
+	p_rsa_asn1.c
+	pbkdf.c
+	sign.c
+)
+
+
+add_executable(
+	example_sign
+
+	example_sign.c
+)
+
+target_link_libraries(example_sign crypto)
diff --git a/crypto/evp/asn1.c b/crypto/evp/asn1.c
new file mode 100644
index 0000000..50bdb06
--- /dev/null
+++ b/crypto/evp/asn1.c
@@ -0,0 +1,170 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.] */
+
+#include <openssl/evp.h>
+
+#include <openssl/asn1.h>
+#include <openssl/err.h>
+#include <openssl/obj.h>
+#include <openssl/x509.h>
+
+#include "internal.h"
+
+
+EVP_PKEY *d2i_PrivateKey(int type, EVP_PKEY **out, const uint8_t **inp,
+                         long len) {
+  EVP_PKEY *ret;
+
+  if (out == NULL || *out == NULL) {
+    ret = EVP_PKEY_new();
+    if (ret == NULL) {
+      OPENSSL_PUT_ERROR(EVP, d2i_PrivateKey, ERR_R_EVP_LIB);
+      return NULL;
+    }
+  } else {
+    ret = *out;
+  }
+
+  if (!EVP_PKEY_set_type(ret, type)) {
+    OPENSSL_PUT_ERROR(EVP, d2i_PrivateKey, EVP_R_UNKNOWN_PUBLIC_KEY_TYPE);
+    goto err;
+  }
+
+  if (!ret->ameth->old_priv_decode ||
+      !ret->ameth->old_priv_decode(ret, inp, len)) {
+    if (ret->ameth->priv_decode) {
+      PKCS8_PRIV_KEY_INFO *p8 = d2i_PKCS8_PRIV_KEY_INFO(NULL, inp, len);
+      if (!p8) {
+        goto err;
+      }
+      EVP_PKEY_free(ret);
+      ret = EVP_PKCS82PKEY(p8);
+      PKCS8_PRIV_KEY_INFO_free(p8);
+    } else {
+      OPENSSL_PUT_ERROR(EVP, d2i_PrivateKey, ERR_R_ASN1_LIB);
+      goto err;
+    }
+  }
+
+  if (out != NULL) {
+    *out = ret;
+  }
+  return ret;
+
+err:
+  if (ret != NULL && (out == NULL || *out != ret)) {
+    EVP_PKEY_free(ret);
+  }
+  return NULL;
+}
+
+EVP_PKEY *d2i_AutoPrivateKey(EVP_PKEY **out, const uint8_t **inp, long len) {
+  STACK_OF(ASN1_TYPE) *inkey;
+  const uint8_t *p;
+  int keytype;
+  p = *inp;
+
+  /* Dirty trick: read in the ASN1 data into out STACK_OF(ASN1_TYPE):
+   * by analyzing it we can determine the passed structure: this
+   * assumes the input is surrounded by an ASN1 SEQUENCE. */
+  inkey = d2i_ASN1_SEQUENCE_ANY(NULL, &p, len);
+  /* Since we only need to discern "traditional format" RSA and DSA
+   * keys we can just count the elements. */
+  if (sk_ASN1_TYPE_num(inkey) == 6) {
+    keytype = EVP_PKEY_DSA;
+  } else if (sk_ASN1_TYPE_num(inkey) == 4) {
+    keytype = EVP_PKEY_EC;
+  } else if (sk_ASN1_TYPE_num(inkey) == 3) {
+    OPENSSL_PUT_ERROR(EVP, d2i_AutoPrivateKey, EVP_R_UNSUPPORTED_PUBLIC_KEY_TYPE);
+    return 0;
+
+    /* This seems to be PKCS8, not traditional format */
+    PKCS8_PRIV_KEY_INFO *p8 = d2i_PKCS8_PRIV_KEY_INFO(NULL, inp, len);
+    EVP_PKEY *ret;
+
+    sk_ASN1_TYPE_pop_free(inkey, ASN1_TYPE_free);
+    if (!p8) {
+      OPENSSL_PUT_ERROR(EVP, d2i_AutoPrivateKey,
+                        EVP_R_UNSUPPORTED_PUBLIC_KEY_TYPE);
+      return NULL;
+    }
+    ret = EVP_PKCS82PKEY(p8);
+    PKCS8_PRIV_KEY_INFO_free(p8);
+    if (out) {
+      *out = ret;
+    }
+    return ret;
+  } else {
+    keytype = EVP_PKEY_RSA;
+  }
+
+  sk_ASN1_TYPE_pop_free(inkey, ASN1_TYPE_free);
+  return d2i_PrivateKey(keytype, out, inp, len);
+}
+
+int i2d_PublicKey(EVP_PKEY *key, uint8_t **outp) {
+  switch (key->type) {
+    case EVP_PKEY_RSA:
+      return i2d_RSAPublicKey(key->pkey.rsa, outp);
+    case EVP_PKEY_DSA:
+      return i2d_DSAPublicKey(key->pkey.dsa, outp);
+    case EVP_PKEY_EC:
+      return i2o_ECPublicKey(key->pkey.ec, outp);
+    default:
+      OPENSSL_PUT_ERROR(EVP, i2d_PublicKey, EVP_R_UNSUPPORTED_PUBLIC_KEY_TYPE);
+      return -1;
+  }
+}
diff --git a/crypto/evp/digestsign.c b/crypto/evp/digestsign.c
new file mode 100644
index 0000000..08968ed
--- /dev/null
+++ b/crypto/evp/digestsign.c
@@ -0,0 +1,212 @@
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project 2006.
+ */
+/* ====================================================================
+ * Copyright (c) 2006,2007 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    licensing@OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com). */
+
+#include <openssl/evp.h>
+
+#include <openssl/digest.h>
+#include <openssl/err.h>
+
+#include "internal.h"
+#include "../digest/internal.h"
+
+
+/* md_begin_digset is a callback from the |EVP_MD_CTX| code that is called when
+ * a new digest is begun. */
+static int md_begin_digest(EVP_MD_CTX *ctx) {
+  int r = EVP_PKEY_CTX_ctrl(ctx->pctx, -1, EVP_PKEY_OP_TYPE_SIG,
+                            EVP_PKEY_CTRL_DIGESTINIT, 0, ctx);
+  return r > 0 || r == -2;
+}
+
+static const struct evp_md_pctx_ops md_pctx_ops = {
+  EVP_PKEY_CTX_free,
+  EVP_PKEY_CTX_dup,
+  md_begin_digest,
+};
+
+static int do_sigver_init(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx,
+                          const EVP_MD *type, ENGINE *e, EVP_PKEY *pkey,
+                          int is_verify) {
+  if (ctx->pctx == NULL) {
+    ctx->pctx = EVP_PKEY_CTX_new(pkey, e);
+  }
+  if (ctx->pctx == NULL) {
+    return 0;
+  }
+  ctx->pctx_ops = &md_pctx_ops;
+
+  if (type == NULL) {
+    type = EVP_sha1();
+  }
+
+  if (type == NULL) {
+    OPENSSL_PUT_ERROR(EVP, do_sigver_init, EVP_R_NO_DEFAULT_DIGEST);
+    return 0;
+  }
+
+  if (is_verify) {
+    if (ctx->pctx->pmeth->verifyctx_init) {
+      if (ctx->pctx->pmeth->verifyctx_init(ctx->pctx, ctx) <= 0) {
+        return 0;
+      }
+      ctx->pctx->operation = EVP_PKEY_OP_VERIFYCTX;
+    } else if (EVP_PKEY_verify_init(ctx->pctx) <= 0) {
+      return 0;
+    }
+  } else {
+    if (ctx->pctx->pmeth->signctx_init) {
+      if (ctx->pctx->pmeth->signctx_init(ctx->pctx, ctx) <= 0) {
+        return 0;
+      }
+      ctx->pctx->operation = EVP_PKEY_OP_SIGNCTX;
+    } else if (EVP_PKEY_sign_init(ctx->pctx) <= 0) {
+      return 0;
+    }
+  }
+  if (EVP_PKEY_CTX_set_signature_md(ctx->pctx, type) <= 0) {
+    return 0;
+  }
+  if (pctx) {
+    *pctx = ctx->pctx;
+  }
+  if (!EVP_DigestInit_ex(ctx, type, e)) {
+    return 0;
+  }
+  return 1;
+}
+
+int EVP_DigestSignInit(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx, const EVP_MD *type,
+                       ENGINE *e, EVP_PKEY *pkey) {
+  return do_sigver_init(ctx, pctx, type, e, pkey, 0);
+}
+
+int EVP_DigestVerifyInit(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx,
+                         const EVP_MD *type, ENGINE *e, EVP_PKEY *pkey) {
+  return do_sigver_init(ctx, pctx, type, e, pkey, 1);
+}
+
+int EVP_DigestSignUpdate(EVP_MD_CTX *ctx, const void *data, size_t len) {
+  return EVP_DigestUpdate(ctx, data, len);
+}
+
+int EVP_DigestVerifyUpdate(EVP_MD_CTX *ctx, const void *data, size_t len) {
+  return EVP_DigestUpdate(ctx, data, len);
+}
+
+int EVP_DigestSignFinal(EVP_MD_CTX *ctx, uint8_t *out_sig,
+                        size_t *out_sig_len) {
+  int r = 0;
+  const int has_signctx = ctx->pctx->pmeth->signctx != NULL;
+
+  if (out_sig) {
+    EVP_MD_CTX tmp_ctx;
+    uint8_t md[EVP_MAX_MD_SIZE];
+    unsigned int mdlen;
+
+    EVP_MD_CTX_init(&tmp_ctx);
+    if (!EVP_MD_CTX_copy_ex(&tmp_ctx, ctx)) {
+      return 0;
+    }
+    if (has_signctx) {
+      r = tmp_ctx.pctx->pmeth->signctx(tmp_ctx.pctx, out_sig, out_sig_len, &tmp_ctx);
+    } else {
+      r = EVP_DigestFinal_ex(&tmp_ctx, md, &mdlen);
+    }
+    EVP_MD_CTX_cleanup(&tmp_ctx);
+    if (has_signctx || !r) {
+      return r;
+    }
+    if (EVP_PKEY_sign(ctx->pctx, out_sig, out_sig_len, md, mdlen) <= 0) {
+      return 0;
+    }
+  } else {
+    if (has_signctx) {
+      if (ctx->pctx->pmeth->signctx(ctx->pctx, out_sig, out_sig_len, ctx) <= 0) {
+        return 0;
+      }
+    } else {
+      size_t s = EVP_MD_size(ctx->digest);
+      if (EVP_PKEY_sign(ctx->pctx, out_sig, out_sig_len, NULL, s) <= 0) {
+        return 0;
+      }
+    }
+  }
+  return 1;
+}
+
+int EVP_DigestVerifyFinal(EVP_MD_CTX *ctx, const uint8_t *sig,
+                          size_t sig_len) {
+  EVP_MD_CTX tmp_ctx;
+  uint8_t md[EVP_MAX_MD_SIZE];
+  int r;
+  unsigned int mdlen;
+  const int has_verifyctx = ctx->pctx->pmeth->verifyctx != NULL;
+
+  EVP_MD_CTX_init(&tmp_ctx);
+  if (!EVP_MD_CTX_copy_ex(&tmp_ctx, ctx)) {
+    return -1;
+  }
+  if (has_verifyctx) {
+    r = tmp_ctx.pctx->pmeth->verifyctx(tmp_ctx.pctx, sig, sig_len, &tmp_ctx);
+  } else {
+    r = EVP_DigestFinal_ex(&tmp_ctx, md, &mdlen);
+  }
+
+  EVP_MD_CTX_cleanup(&tmp_ctx);
+  if (has_verifyctx || !r) {
+    return r;
+  }
+  return EVP_PKEY_verify(ctx->pctx, sig, sig_len, md, mdlen);
+}
diff --git a/crypto/evp/evp.c b/crypto/evp/evp.c
new file mode 100644
index 0000000..1d6fd8c
--- /dev/null
+++ b/crypto/evp/evp.c
@@ -0,0 +1,425 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.] */
+
+#include <openssl/evp.h>
+
+#include <assert.h>
+
+#include <openssl/bio.h>
+#include <openssl/dh.h>
+#include <openssl/dsa.h>
+#include <openssl/ec.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+#include <openssl/obj.h>
+#include <openssl/rsa.h>
+
+#include "internal.h"
+
+
+extern const EVP_PKEY_ASN1_METHOD ec_asn1_meth;
+extern const EVP_PKEY_ASN1_METHOD hmac_asn1_meth;
+extern const EVP_PKEY_ASN1_METHOD rsa_asn1_meth;
+
+EVP_PKEY *EVP_PKEY_new() {
+  EVP_PKEY *ret;
+
+  ret = OPENSSL_malloc(sizeof(EVP_PKEY));
+  if (ret == NULL) {
+    OPENSSL_PUT_ERROR(EVP, EVP_PKEY_new, ERR_R_MALLOC_FAILURE);
+    return NULL;
+  }
+
+  memset(ret, 0, sizeof(EVP_PKEY));
+  ret->type = EVP_PKEY_NONE;
+  ret->references = 1;
+
+  return ret;
+}
+
+static void free_it(EVP_PKEY *pkey) {
+  if (pkey->ameth && pkey->ameth->pkey_free) {
+    pkey->ameth->pkey_free(pkey);
+    pkey->pkey.ptr = NULL;
+    pkey->type = EVP_PKEY_NONE;
+  }
+}
+
+void EVP_PKEY_free(EVP_PKEY *pkey) {
+  if (pkey == NULL) {
+    return;
+  }
+
+  if (CRYPTO_add(&pkey->references, -1, CRYPTO_LOCK_EVP_PKEY)) {
+    return;
+  }
+
+  free_it(pkey);
+  if (pkey->attributes) {
+    /* TODO(fork): layering: X509_ATTRIBUTE_free is an X.509 function. In
+     * practice this path isn't called but should be removed in the future. */
+    /*sk_X509_ATTRIBUTE_pop_free(pkey->attributes, X509_ATTRIBUTE_free);*/
+    assert(0);
+  }
+  OPENSSL_free(pkey);
+}
+
+int EVP_PKEY_cmp(const EVP_PKEY *a, const EVP_PKEY *b) {
+  if (a->type != b->type) {
+    return -1;
+  }
+
+  if (a->ameth) {
+    int ret;
+    /* Compare parameters if the algorithm has them */
+    if (a->ameth->param_cmp) {
+      ret = a->ameth->param_cmp(a, b);
+      if (ret <= 0)
+        return ret;
+    }
+
+    if (a->ameth->pub_cmp) {
+      return a->ameth->pub_cmp(a, b);
+    }
+  }
+
+  return -2;
+}
+
+EVP_PKEY *EVP_PKEY_dup(EVP_PKEY *pkey) {
+  CRYPTO_add(&pkey->references, 1, CRYPTO_LOCK_EVP_PKEY);
+  return pkey;
+}
+
+int EVP_PKEY_copy_parameters(EVP_PKEY *to, const EVP_PKEY *from) {
+  if (to->type != from->type) {
+    OPENSSL_PUT_ERROR(EVP, EVP_PKEY_copy_parameters, EVP_R_DIFFERENT_KEY_TYPES);
+    goto err;
+  }
+
+  if (EVP_PKEY_missing_parameters(from)) {
+    OPENSSL_PUT_ERROR(EVP, EVP_PKEY_copy_parameters, EVP_R_MISSING_PARAMETERS);
+    goto err;
+  }
+
+  if (from->ameth && from->ameth->param_copy) {
+    return from->ameth->param_copy(to, from);
+  }
+
+err:
+  return 0;
+}
+
+int EVP_PKEY_missing_parameters(const EVP_PKEY *pkey) {
+  if (pkey->ameth && pkey->ameth->param_missing) {
+    return pkey->ameth->param_missing(pkey);
+  }
+  return 0;
+}
+
+int EVP_PKEY_size(const EVP_PKEY *pkey) {
+  if (pkey && pkey->ameth && pkey->ameth->pkey_size) {
+    return pkey->ameth->pkey_size(pkey);
+  }
+  return 0;
+}
+
+int EVP_PKEY_bits(EVP_PKEY *pkey) {
+  if (pkey && pkey->ameth && pkey->ameth->pkey_bits) {
+    return pkey->ameth->pkey_bits(pkey);
+  }
+  return 0;
+}
+
+int EVP_PKEY_id(const EVP_PKEY *pkey) {
+  return pkey->type;
+}
+
+/* TODO(fork): remove the first argument. */
+const EVP_PKEY_ASN1_METHOD *EVP_PKEY_asn1_find(ENGINE **pengine, int nid) {
+  switch (nid) {
+    case EVP_PKEY_RSA:
+    case EVP_PKEY_RSA2:
+      return &rsa_asn1_meth;
+    case EVP_PKEY_HMAC:
+      return &hmac_asn1_meth;
+    case EVP_PKEY_EC:
+      return &ec_asn1_meth;
+    default:
+      return NULL;
+  }
+}
+
+int EVP_PKEY_type(int nid) {
+  const EVP_PKEY_ASN1_METHOD *meth = EVP_PKEY_asn1_find(NULL, nid);
+  if (meth == NULL) {
+    return NID_undef;
+  }
+  return meth->pkey_id;
+}
+
+EVP_PKEY *EVP_PKEY_new_mac_key(int type, ENGINE *e, const uint8_t *mac_key,
+                               size_t mac_key_len) {
+  EVP_PKEY_CTX *mac_ctx = NULL;
+  EVP_PKEY *ret = NULL;
+
+  mac_ctx = EVP_PKEY_CTX_new_id(type, e);
+  if (!mac_ctx) {
+    return NULL;
+  }
+
+  if (EVP_PKEY_keygen_init(mac_ctx) <= 0 ||
+      EVP_PKEY_CTX_ctrl(mac_ctx, -1, EVP_PKEY_OP_KEYGEN,
+                        EVP_PKEY_CTRL_SET_MAC_KEY, mac_key_len,
+                        (uint8_t *)mac_key) <= 0 ||
+      EVP_PKEY_keygen(mac_ctx, &ret) <= 0) {
+    ret = NULL;
+    goto merr;
+  }
+
+merr:
+  if (mac_ctx)
+    EVP_PKEY_CTX_free(mac_ctx);
+  return ret;
+}
+
+int EVP_PKEY_set1_RSA(EVP_PKEY *pkey, RSA *key) {
+  if (EVP_PKEY_assign_RSA(pkey, key)) {
+    RSA_up_ref(key);
+    return 1;
+  }
+  return 0;
+}
+
+int EVP_PKEY_assign_RSA(EVP_PKEY *pkey, RSA *key) {
+  return EVP_PKEY_assign(pkey, EVP_PKEY_RSA, key);
+}
+
+RSA *EVP_PKEY_get1_RSA(EVP_PKEY *pkey) {
+  if (pkey->type != EVP_PKEY_RSA) {
+    OPENSSL_PUT_ERROR(EVP, EVP_PKEY_get1_RSA, EVP_R_EXPECTING_AN_RSA_KEY);
+    return NULL;
+  }
+  RSA_up_ref(pkey->pkey.rsa);
+  return pkey->pkey.rsa;
+}
+
+int EVP_PKEY_set1_DSA(EVP_PKEY *pkey, DSA *key) {
+  if (EVP_PKEY_assign_DSA(pkey, key)) {
+    DSA_up_ref(key);
+    return 1;
+  }
+  return 0;
+}
+
+int EVP_PKEY_assign_DSA(EVP_PKEY *pkey, DSA *key) {
+  return EVP_PKEY_assign(pkey, EVP_PKEY_DSA, key);
+}
+
+DSA *EVP_PKEY_get1_DSA(EVP_PKEY *pkey) {
+  if (pkey->type != EVP_PKEY_DSA) {
+    OPENSSL_PUT_ERROR(EVP, EVP_PKEY_get1_DSA, EVP_R_EXPECTING_A_DSA_KEY);
+    return NULL;
+  }
+  DSA_up_ref(pkey->pkey.dsa);
+  return pkey->pkey.dsa;
+}
+
+int EVP_PKEY_set1_EC_KEY(EVP_PKEY *pkey, EC_KEY *key) {
+  if (EVP_PKEY_assign_EC_KEY(pkey, key)) {
+    EC_KEY_up_ref(key);
+    return 1;
+  }
+  return 0;
+}
+
+int EVP_PKEY_assign_EC_KEY(EVP_PKEY *pkey, EC_KEY *key) {
+  return EVP_PKEY_assign(pkey, EVP_PKEY_EC, key);
+}
+
+EC_KEY *EVP_PKEY_get1_EC_KEY(EVP_PKEY *pkey) {
+  if (pkey->type != EVP_PKEY_EC) {
+    OPENSSL_PUT_ERROR(EVP, EVP_PKEY_get1_EC_KEY, EVP_R_EXPECTING_AN_EC_KEY_KEY);
+    return NULL;
+  }
+  EC_KEY_up_ref(pkey->pkey.ec);
+  return pkey->pkey.ec;
+}
+
+int EVP_PKEY_set1_DH(EVP_PKEY *pkey, DH *key) {
+  if (EVP_PKEY_assign_DH(pkey, key)) {
+    DH_up_ref(key);
+    return 1;
+  }
+  return 0;
+}
+
+int EVP_PKEY_assign_DH(EVP_PKEY *pkey, DH *key) {
+  return EVP_PKEY_assign(pkey, EVP_PKEY_EC, key);
+}
+
+DH *EVP_PKEY_get1_DH(EVP_PKEY *pkey) {
+  if (pkey->type != EVP_PKEY_DH) {
+    OPENSSL_PUT_ERROR(EVP, EVP_PKEY_get1_DH, EVP_R_EXPECTING_A_DH_KEY);
+    return NULL;
+  }
+  DH_up_ref(pkey->pkey.dh);
+  return pkey->pkey.dh;
+}
+
+int EVP_PKEY_assign(EVP_PKEY *pkey, int type, void *key) {
+  if (!EVP_PKEY_set_type(pkey, type)) {
+    return 0;
+  }
+  pkey->pkey.ptr = key;
+  return key != NULL;
+}
+
+const EVP_PKEY_ASN1_METHOD *EVP_PKEY_asn1_find_str(ENGINE **pengine,
+                                                   const char *name,
+                                                   size_t len) {
+  if (len == 3 && memcmp(name, "RSA", 3) == 0) {
+    return &rsa_asn1_meth;
+  } else if (len == 4 && memcmp(name, "HMAC", 4) == 0) {
+    return &hmac_asn1_meth;
+  } if (len == 2 && memcmp(name, "EC", 4) == 0) {
+    return &ec_asn1_meth;
+  }
+  return NULL;
+}
+
+int EVP_PKEY_set_type(EVP_PKEY *pkey, int type) {
+  const EVP_PKEY_ASN1_METHOD *ameth;
+
+  if (pkey && pkey->pkey.ptr) {
+    free_it(pkey);
+  }
+
+  ameth = EVP_PKEY_asn1_find(NULL, type);
+  if (ameth == NULL) {
+    OPENSSL_PUT_ERROR(EVP, EVP_PKEY_set_type, EVP_R_UNSUPPORTED_ALGORITHM);
+    ERR_add_error_dataf("algorithm %d (%s)", type, OBJ_nid2sn(type));
+    return 0;
+  }
+
+  if (pkey) {
+    pkey->ameth = ameth;
+    pkey->type = pkey->ameth->pkey_id;
+  }
+
+  return 1;
+}
+
+
+
+int EVP_PKEY_cmp_parameters(const EVP_PKEY *a, const EVP_PKEY *b) {
+  if (a->type != b->type) {
+    return -1;
+  }
+  if (a->ameth && a->ameth->param_cmp) {
+    return a->ameth->param_cmp(a, b);
+  }
+  return -2;
+}
+
+static int print_unsupported(BIO *out, const EVP_PKEY *pkey, int indent,
+                             const char *kstr) {
+  BIO_indent(out, indent, 128);
+  BIO_printf(out, "%s algorithm \"%s\" unsupported\n", kstr,
+             OBJ_nid2ln(pkey->type));
+  return 1;
+}
+
+int EVP_PKEY_print_public(BIO *out, const EVP_PKEY *pkey, int indent,
+                          ASN1_PCTX *pctx) {
+  if (pkey->ameth && pkey->ameth->pub_print) {
+    return pkey->ameth->pub_print(out, pkey, indent, pctx);
+  }
+
+  return print_unsupported(out, pkey, indent, "Public Key");
+}
+
+int EVP_PKEY_print_private(BIO *out, const EVP_PKEY *pkey, int indent,
+                           ASN1_PCTX *pctx) {
+  if (pkey->ameth && pkey->ameth->priv_print) {
+    return pkey->ameth->priv_print(out, pkey, indent, pctx);
+  }
+
+  return print_unsupported(out, pkey, indent, "Private Key");
+}
+
+int EVP_PKEY_print_params(BIO *out, const EVP_PKEY *pkey, int indent,
+                          ASN1_PCTX *pctx) {
+  if (pkey->ameth && pkey->ameth->param_print) {
+    return pkey->ameth->param_print(out, pkey, indent, pctx);
+  }
+
+  return print_unsupported(out, pkey, indent, "Parameters");
+}
+
+int EVP_PKEY_CTX_set_signature_md(EVP_PKEY_CTX *ctx, const EVP_MD *md) {
+  return EVP_PKEY_CTX_ctrl(ctx, -1, EVP_PKEY_OP_TYPE_SIG, EVP_PKEY_CTRL_MD, 0,
+                           (void *)md);
+}
+
+int EVP_PKEY_CTX_get_signature_md(EVP_PKEY_CTX *ctx, const EVP_MD **out_md) {
+  return EVP_PKEY_CTX_ctrl(ctx, -1, EVP_PKEY_OP_TYPE_SIG, EVP_PKEY_CTRL_GET_MD,
+                           0, (void *)out_md);
+}
+
+void OpenSSL_add_all_algorithms() {}
+
+void EVP_cleanup() {}
diff --git a/crypto/evp/evp.h b/crypto/evp/evp.h
new file mode 100644
index 0000000..ce40aa5
--- /dev/null
+++ b/crypto/evp/evp.h
@@ -0,0 +1,819 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.] */
+
+#ifndef OPENSSL_HEADER_EVP_H
+#define OPENSSL_HEADER_EVP_H
+
+#include <openssl/base.h>
+#include <openssl/stack.h>
+
+/* OpenSSL included digest and cipher functions in this header so we include
+ * them for users that still expect that. */
+#include <openssl/cipher.h>
+#include <openssl/digest.h>
+#include <openssl/mem.h>
+#include <openssl/obj.h>
+#include <openssl/thread.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+/* EVP abstracts over public/private key algorithms. */
+
+
+/* Public key objects. */
+
+/* EVP_PKEY_new creates a new, empty public-key object and returns it or NULL
+ * on allocation failure. */
+EVP_PKEY *EVP_PKEY_new();
+
+/* EVP_PKEY_free frees all data referenced by |pkey| and then frees |pkey|
+ * itself. */
+void EVP_PKEY_free(EVP_PKEY *pkey);
+
+/* EVP_PKEY_cmp compares |a| and |b| and returns one if they are equal, zero if
+ * not and a negative number on error.
+ *
+ * WARNING: this differs from the traditional return value of a "cmp"
+ * function. */
+int EVP_PKEY_cmp(const EVP_PKEY *a, const EVP_PKEY *b);
+
+/* EVP_PKEY_dup adds one to the reference count of |pkey| and returns
+ * |pkey|. */
+EVP_PKEY *EVP_PKEY_dup(EVP_PKEY *pkey);
+
+/* EVP_PKEY_copy_parameters sets the parameters of |to| to equal the parameters
+ * of |from|. It returns one on success and zero on error. */
+int EVP_PKEY_copy_parameters(EVP_PKEY *to, const EVP_PKEY *from);
+
+/* EVP_PKEY_missing_parameters returns one if |pkey| is missing needed
+ * parameters or zero if not, or if the algorithm doesn't take parameters. */
+int EVP_PKEY_missing_parameters(const EVP_PKEY *pkey);
+
+/* EVP_PKEY_size returns the "size", in bytes, of |pkey|. For example, for an
+ * RSA key this returns the number of bytes needed to represent the modulus. */
+int EVP_PKEY_size(const EVP_PKEY *pkey);
+
+/* EVP_PKEY_bits returns the "size", in bits, of |pkey|. For example, for an
+ * RSA key, this returns the bit length of the modulus. */
+int EVP_PKEY_bits(EVP_PKEY *pkey);
+
+/* EVP_PKEY_id returns the type of |pkey|, which is one of the |EVP_PKEY_*|
+ * values. */
+int EVP_PKEY_id(const EVP_PKEY *pkey);
+
+/* EVP_PKEY_type returns a canonicalised form of |NID|. For example,
+ * |EVP_PKEY_RSA2| will be turned into |EVP_PKEY_RSA|. */
+int EVP_PKEY_type(int nid);
+
+/* EVP_PKEY_new_mac_key allocates a fresh |EVP_PKEY| of the given type (e.g.
+ * |EVP_PKEY_HMAC|), sets |mac_key| as the MAC key and "generates" a new key,
+ * suitable for signing. It returns the fresh |EVP_PKEY|, or NULL on error. */
+EVP_PKEY *EVP_PKEY_new_mac_key(int type, ENGINE *engine, const uint8_t *mac_key,
+                               size_t mac_key_len);
+
+
+/* Getting and setting concrete public key types.
+ *
+ * The following functions get and set the underlying public key in an
+ * |EVP_PKEY| object. The |set1| functions take a additional reference to the
+ * underlying key and return one on success or zero on error. The |assign|
+ * functions adopt the caller's reference. The getters return a fresh reference
+ * to the underlying object. */
+
+int EVP_PKEY_set1_RSA(EVP_PKEY *pkey, RSA *key);
+int EVP_PKEY_assign_RSA(EVP_PKEY *pkey, RSA *key);
+RSA *EVP_PKEY_get1_RSA(EVP_PKEY *pkey);
+
+int EVP_PKEY_set1_DSA(EVP_PKEY *pkey, struct dsa_st *key);
+int EVP_PKEY_assign_DSA(EVP_PKEY *pkey, DSA *key);
+struct dsa_st *EVP_PKEY_get1_DSA(EVP_PKEY *pkey);
+
+int EVP_PKEY_set1_EC_KEY(EVP_PKEY *pkey, struct ec_key_st *key);
+int EVP_PKEY_assign_EC_KEY(EVP_PKEY *pkey, EC_KEY *key);
+struct ec_key_st *EVP_PKEY_get1_EC_KEY(EVP_PKEY *pkey);
+
+int EVP_PKEY_set1_DH(EVP_PKEY *pkey, struct dh_st *key);
+int EVP_PKEY_assign_DH(EVP_PKEY *pkey, DH *key);
+struct dh_st *EVP_PKEY_get1_DH(EVP_PKEY *pkey);
+
+#define EVP_PKEY_NONE NID_undef
+#define EVP_PKEY_RSA NID_rsaEncryption
+#define EVP_PKEY_RSA2 NID_rsa
+#define EVP_PKEY_DSA NID_dsa
+#define EVP_PKEY_DH NID_dhKeyAgreement
+#define EVP_PKEY_DHX NID_dhpublicnumber
+#define EVP_PKEY_EC NID_X9_62_id_ecPublicKey
+#define EVP_PKEY_HMAC NID_hmac
+
+/* EVP_PKEY_assign sets the underlying key of |pkey| to |key|, which must be of
+ * the given type. The |type| argument should be one of the |EVP_PKEY_*|
+ * values. */
+int EVP_PKEY_assign(EVP_PKEY *pkey, int type, void *key);
+
+/* EVP_PKEY_set_type sets the type of |pkey| to |type|, which should be one of
+ * the |EVP_PKEY_*| values. It returns one if sucessful or zero otherwise. If
+ * |pkey| is NULL, it simply reports whether the type is known. */
+int EVP_PKEY_set_type(EVP_PKEY *pkey, int type);
+
+/* EVP_PKEY_cmp_parameters compares the parameters of |a| and |b|. It returns
+ * one if they match, zero if not, or a negative number of on error.
+ *
+ * WARNING: the return value differs from the usual return value convention. */
+int EVP_PKEY_cmp_parameters(const EVP_PKEY *a, const EVP_PKEY *b);
+
+
+/* ASN.1 functions */
+
+/* d2i_PrivateKey parses an ASN.1, DER-encoded, private key from |len| bytes at
+ * |*inp|. If |out| is not NULL then, on exit, a pointer to the result is in
+ * |*out|. If |*out| is already non-NULL on entry then the result is written
+ * directly into |*out|, otherwise a fresh |EVP_PKEY| is allocated. On
+ * successful exit, |*inp| is advanced past the DER structure. It returns the
+ * result or NULL on error. */
+EVP_PKEY *d2i_PrivateKey(int type, EVP_PKEY **out, const uint8_t **inp,
+                         long len);
+
+/* d2i_AutoPrivateKey acts the same as |d2i_PrivateKey|, but detects the type
+ * of the private key. */
+EVP_PKEY *d2i_AutoPrivateKey(EVP_PKEY **out, const uint8_t **inp, long len);
+
+/* i2d_PrivateKey marshals a private key from |key| to an ASN.1, DER
+ * structure. If |outp| is not NULL then the result is written to |*outp| and
+ * |*outp| is advanced just past the output. It returns the number of bytes in
+ * the result, whether written or not, or a negative value on error. */
+int i2d_PrivateKey(const EVP_PKEY *key, uint8_t **outp);
+
+/* i2d_PublicKey marshals a public key from |key| to an ASN.1, DER
+ * structure. If |outp| is not NULL then the result is written to |*outp| and
+ * |*outp| is advanced just past the output. It returns the number of bytes in
+ * the result, whether written or not, or a negative value on error. */
+int i2d_PublicKey(EVP_PKEY *key, uint8_t **outp);
+
+
+/* Signing */
+
+/* EVP_DigestSignInit sets up |ctx| for a signing operation with |type| and
+ * |pkey|. The |ctx| argument must have been initialised with
+ * |EVP_MD_CTX_init|. If |pctx| is not NULL, the |EVP_PKEY_CTX| of the signing
+ * operation will be written to |*pctx|; this can be used to set alternative
+ * signing options.
+ *
+ * It returns one on success, or <= 0 on error. WARNING: this differs from the
+ * usual OpenSSL return convention. */
+int EVP_DigestSignInit(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx, const EVP_MD *type,
+                       ENGINE *e, EVP_PKEY *pkey);
+
+/* EVP_DigestSignUpdate appends |len| bytes from |data| to the data which will
+ * be signed in |EVP_DigestSignFinal|. It returns one on success and zero
+ * otherwise. */
+int EVP_DigestSignUpdate(EVP_MD_CTX *ctx, const void *data, size_t len);
+
+/* EVP_DigestSignFinal signs the data that has been included by one or more
+ * calls to |EVP_DigestSignUpdate|. If |out_sig| is NULL then |*out_sig_len| is
+ * set to the maximum number of output bytes. Otherwise, on entry,
+ * |*out_sig_len| must contain the length of the |out_sig| buffer. If the call
+ * is successful, the signature is written to |out_sig| and |*out_sig_len| is
+ * set to its length.
+ *
+ * It returns one on success and <= 0 on error. WARNING: this differs from the
+ * usual, OpenSSL return value convention. */
+int EVP_DigestSignFinal(EVP_MD_CTX *ctx, uint8_t *out_sig, size_t *out_sig_len);
+
+
+/* Verifying */
+
+/* EVP_DigestVerifyInit sets up |ctx| for a signature verification operation
+ * with |type| and |pkey|. The |ctx| argument must have been initialised with
+ * |EVP_MD_CTX_init|. If |pctx| is not NULL, the |EVP_PKEY_CTX| of the signing
+ * operation will be written to |*pctx|; this can be used to set alternative
+ * signing options.
+ *
+ * It returns one on success, or <= 0 on error. WARNING: this differs from the
+ * usual OpenSSL return convention. */
+int EVP_DigestVerifyInit(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx,
+                         const EVP_MD *type, ENGINE *e, EVP_PKEY *pkey);
+
+/* EVP_DigestVerifyUpdate appends |len| bytes from |data| to the data which
+ * will be verified by |EVP_DigestVerifyFinal|. It returns one on success and
+ * zero otherwise. */
+int EVP_DigestVerifyUpdate(EVP_MD_CTX *ctx, const void *data, size_t len);
+
+/* EVP_DigestVerifyFinal verifies that |sig_len| bytes of |sig| are a valid
+ * signature for the data that has been included by one or more calls to
+ * |EVP_DigestVerifyUpdate|.
+ *
+ * It returns one on success and <= 0 on error. WARNING: this differs from the
+ * usual return value convention. */
+int EVP_DigestVerifyFinal(EVP_MD_CTX *ctx, const uint8_t *sig,
+                          size_t sig_len);
+
+
+/* Signing (old functions) */
+
+/* EVP_SignInit_ex configures |ctx|, which must already have been initialised,
+ * for a fresh signing operation using the hash function |type|. It returns one
+ * on success and zero otherwise.
+ *
+ * (In order to initialise |ctx|, either obtain it initialised with
+ * |EVP_MD_CTX_create|, or use |EVP_MD_CTX_init|.) */
+int EVP_SignInit_ex(EVP_MD_CTX *ctx, const EVP_MD *type, ENGINE *impl);
+
+/* EVP_SignInit is a deprecated version of |EVP_SignInit_ex|.
+ *
+ * TODO(fork): remove. */
+int EVP_SignInit(EVP_MD_CTX *ctx, const EVP_MD *type);
+
+/* EVP_SignUpdate appends |len| bytes from |data| to the data which will be
+ * signed in |EVP_SignFinal|. */
+int EVP_SignUpdate(EVP_MD_CTX *ctx, const void *data, size_t len);
+
+/* EVP_SignFinal signs the data that has been included by one or more calls to
+ * |EVP_SignUpdate|, using the key |pkey|, and writes it to |sig|. On entry,
+ * |sig| must point to at least |EVP_PKEY_size(pkey)| bytes of space. The
+ * actual size of the signature is written to |*out_sig_len|.
+ *
+ * It returns one on success and zero otherwise.
+ *
+ * It does not modify |ctx|, thus it's possible to continue to use |ctx| in
+ * order to sign a longer message. */
+int EVP_SignFinal(const EVP_MD_CTX *ctx, uint8_t *sig,
+                  unsigned int *out_sig_len, EVP_PKEY *pkey);
+
+
+/* Verifying (old functions) */
+
+/* EVP_VerifyInit_ex configures |ctx|, which must already have been
+ * initialised, for a fresh signature verification operation using the hash
+ * function |type|. It returns one on success and zero otherwise.
+ *
+ * (In order to initialise |ctx|, either obtain it initialised with
+ * |EVP_MD_CTX_create|, or use |EVP_MD_CTX_init|.) */
+int EVP_VerifyInit_ex(EVP_MD_CTX *ctx, const EVP_MD *type, ENGINE *impl);
+
+/* EVP_VerifyInit is a deprecated version of |EVP_VerifyInit_ex|.
+ *
+ * TODO(fork): remove. */
+int EVP_VerifyInit(EVP_MD_CTX *ctx, const EVP_MD *type);
+
+/* EVP_VerifyUpdate appends |len| bytes from |data| to the data which will be
+ * signed in |EVP_VerifyFinal|. */
+int EVP_VerifyUpdate(EVP_MD_CTX *ctx, const void *data, size_t len);
+
+/* EVP_VerifyFinal verifies that |sig_len| bytes of |sig| are a valid
+ * signature, by |pkey|, for the data that has been included by one or more
+ * calls to |EVP_VerifyUpdate|.
+ *
+ * It returns one on success and zero otherwise.
+ *
+ * It does not modify |ctx|, thus it's possible to continue to use |ctx| in
+ * order to sign a longer message. */
+int EVP_VerifyFinal(EVP_MD_CTX *ctx, const uint8_t *sig, size_t sig_len,
+                    EVP_PKEY *pkey);
+
+
+/* Printing */
+
+/* EVP_PKEY_print_public prints a textual representation of the public key in
+ * |pkey| to |out|. Returns one on success or zero otherwise. */
+int EVP_PKEY_print_public(BIO *out, const EVP_PKEY *pkey, int indent,
+                          ASN1_PCTX *pctx);
+
+/* EVP_PKEY_print_public prints a textual representation of the private key in
+ * |pkey| to |out|. Returns one on success or zero otherwise. */
+int EVP_PKEY_print_private(BIO *out, const EVP_PKEY *pkey, int indent,
+                           ASN1_PCTX *pctx);
+
+/* EVP_PKEY_print_public prints a textual representation of the parameters in
+ * |pkey| to |out|. Returns one on success or zero otherwise. */
+int EVP_PKEY_print_params(BIO *out, const EVP_PKEY *pkey, int indent,
+                          ASN1_PCTX *pctx);
+
+
+/* Password stretching.
+ *
+ * Password stretching functions take a low-entropy password and apply a slow
+ * function that results in a key suitable for use in symmetric
+ * cryptography. */
+
+/* PKCS5_PBKDF2_HMAC computes |iterations| iterations of PBKDF2 of |password|
+ * and |salt|, using |digest|, and outputs |key_len| bytes to |out_key|. It
+ * returns one on success and zero on error. */
+int PKCS5_PBKDF2_HMAC(const char *password, int password_len,
+                      const uint8_t *salt, size_t salt_len, unsigned iterations,
+                      const EVP_MD *digest, size_t key_len, uint8_t *out_key);
+
+/* PKCS5_PBKDF2_HMAC_SHA1 is the same as PKCS5_PBKDF2_HMAC, but with |digest|
+ * fixed to |EVP_sha1|. */
+int PKCS5_PBKDF2_HMAC_SHA1(const char *password, int password_len,
+                           const uint8_t *salt, size_t salt_len,
+                           unsigned iterations, size_t key_len,
+                           uint8_t *out_key);
+
+
+/* Public key contexts.
+ *
+ * |EVP_PKEY_CTX| objects hold the context of an operation (e.g. signing or
+ * encrypting) that uses a public key. */
+
+/* EVP_PKEY_CTX_new allocates a fresh |EVP_PKEY_CTX| for use with |pkey|. It
+ * returns the context or NULL on error. */
+EVP_PKEY_CTX *EVP_PKEY_CTX_new(EVP_PKEY *pkey, ENGINE *e);
+
+/* EVP_PKEY_CTX_new allocates a fresh |EVP_PKEY_CTX| for a key of type |id|
+ * (e.g. |EVP_PKEY_HMAC|). This can be used for key generation where
+ * |EVP_PKEY_CTX_new| can't be used because there isn't an |EVP_PKEY| to pass
+ * it. It returns the context or NULL on error. */
+EVP_PKEY_CTX *EVP_PKEY_CTX_new_id(int id, ENGINE *e);
+
+/* EVP_KEY_CTX_free frees |ctx| and the data it owns. */
+void EVP_PKEY_CTX_free(EVP_PKEY_CTX *ctx);
+
+/* EVP_PKEY_CTX_dup allocates a fresh |EVP_PKEY_CTX| and sets it equal to the
+ * state of |ctx|. It returns the fresh |EVP_PKEY_CTX| or NULL on error. */
+EVP_PKEY_CTX *EVP_PKEY_CTX_dup(EVP_PKEY_CTX *ctx);
+
+/* EVP_PKEY_CTX_get0_pkey returns the |EVP_PKEY| associated with |ctx|. */
+EVP_PKEY *EVP_PKEY_CTX_get0_pkey(EVP_PKEY_CTX *ctx);
+
+/* EVP_PKEY_CTX_set_app_data sets an opaque pointer on |ctx|. */
+void EVP_PKEY_CTX_set_app_data(EVP_PKEY_CTX *ctx, void *data);
+
+/* EVP_PKEY_CTX_get_app_data returns the opaque pointer from |ctx| that was
+ * previously set with |EVP_PKEY_CTX_set_app_data|, or NULL if none has been
+ * set. */
+void *EVP_PKEY_CTX_get_app_data(EVP_PKEY_CTX *ctx);
+
+/* EVP_PKEY_CTX_ctrl performs |cmd| on |ctx|. The |keytype| and |optype|
+ * arguments can be -1 to specify that any type and operation are acceptable,
+ * otherwise |keytype| must match the type of |ctx| and the bits of |optype|
+ * must intersect the operation flags set on |ctx|.
+ *
+ * The |p1| and |p2| arguments depend on the value of |cmd|.
+ *
+ * It returns -2 if |cmd| is not recognised, -1 on error or a |cmd| specific
+ * value otherwise. */
+int EVP_PKEY_CTX_ctrl(EVP_PKEY_CTX *ctx, int keytype, int optype, int cmd,
+                      int p1, void *p2);
+
+/* EVP_PKEY_sign_init initialises an |EVP_PKEY_CTX| for a signing operation. It
+ * should be called before |EVP_PKEY_sign|.
+ *
+ * It returns one on success or <= 0 on error. WARNING: this differs from the
+ * usual return value convention. */
+int EVP_PKEY_sign_init(EVP_PKEY_CTX *ctx);
+
+/* EVP_PKEY_sign signs |data_len| bytes from |data| using |ctx|. If |sig| is
+ * NULL, the size of the signature is written to |out_sig_len|. Otherwise,
+ * |*sig_len| must contain the number of bytes of space available at |sig|. If
+ * sufficient, the signature will be written to |sig| and |*sig_len| updated
+ * with the true length.
+ *
+ * It returns one on success or zero on error. (Note: this differs from
+ * OpenSSL, which can also return negative values to indicate an error. ) */
+int EVP_PKEY_sign(EVP_PKEY_CTX *ctx, uint8_t *sig, size_t *sig_len,
+                  const uint8_t *data, size_t data_len);
+
+/* EVP_PKEY_verify_init initialises an |EVP_PKEY_CTX| for a signature
+ * verification operation. It should be called before |EVP_PKEY_verify|.
+ *
+ * It returns one on success or <= 0 on error. WARNING: this differs from the
+ * usual return value convention. */
+int EVP_PKEY_verify_init(EVP_PKEY_CTX *ctx);
+
+/* EVP_PKEY_verify verifies that |sig_len| bytes from |sig| are a valid signature
+ * for |data|.
+ *
+ * It returns one on success or zero on error. (Note: this differs from
+ * OpenSSL, which can also return negative values to indicate an error. ) */
+int EVP_PKEY_verify(EVP_PKEY_CTX *ctx, const uint8_t *sig, size_t sig_len,
+                    const uint8_t *data, size_t data_len);
+
+/* EVP_PKEY_encrypt_init initialises an |EVP_PKEY_CTX| for an encryption
+ * operation. It should be called before |EVP_PKEY_encrypt|.
+ *
+ * It returns one on success or <= 0 on error. WARNING: this differs from the
+ * usual return value convention. */
+int EVP_PKEY_encrypt_init(EVP_PKEY_CTX *ctx);
+
+/* EVP_PKEY_encrypt encrypts |in_len| bytes from |in| and writes it to |out|.
+ * TODO(fork): need more details on |out_len|.
+ *
+ * It returns one on success or <= 0 on error. (Note: this differs from
+ * OpenSSL, which can also return negative values to indicate an error. ) */
+int EVP_PKEY_encrypt(EVP_PKEY_CTX *ctx, uint8_t *out, size_t *out_len,
+                     const uint8_t *in, size_t in_len);
+
+/* EVP_PKEY_decrypt_init initialises an |EVP_PKEY_CTX| for a decryption
+ * operation. It should be called before |EVP_PKEY_decrypt|.
+ *
+ * It returns one on success or <= 0 on error. WARNING: this differs from the
+ * usual return value convention. */
+int EVP_PKEY_decrypt_init(EVP_PKEY_CTX *ctx);
+
+/* EVP_PKEY_decrypt decrypts |in_len| bytes from |in|, writes it to |out| and
+ * sets |*outlen| to the number of bytes written.
+ *
+ * It returns one on success or <= 0 on error. (Note: this differs from
+ * OpenSSL, which can also return negative values to indicate an error. ) */
+int EVP_PKEY_decrypt(EVP_PKEY_CTX *ctx, uint8_t *out, size_t *out_len,
+                     const uint8_t *in, size_t in_len);
+
+/* 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|.
+ *
+ * It returns one on success or <= 0 on error. WARNING: this differs from the
+ * usual return value convention. */
+int EVP_PKEY_derive_init(EVP_PKEY_CTX *ctx);
+
+/* EVP_PKEY_derive_set_peer sets the peer's key to be used for key derivation
+ * by |ctx| to |peer|. It should be called after |EVP_PKEY_derive_init|. (For
+ * example, this is used to set the peer's key in (EC)DH.) It returns one on
+ * success and <= 0 on error. WARNING: this differs from the usual return value
+ * convention. */
+int EVP_PKEY_derive_set_peer(EVP_PKEY_CTX *ctx, EVP_PKEY *peer);
+
+/* EVP_PKEY_derive derives a shared key between the two keys configured in
+ * |ctx|. If |key| is non-NULL then, on entry, |out_key_len| must contain the
+ * amount of space at |key|. If sufficient then the shared key will be written
+ * to |key| and |*out_key_len| will be set to the length. If |key| is NULL then
+ * |out_key_len| will be set the length.
+ *
+ * It returns one on success and <= 0 on error. WARNING: this differs from the
+ * usual return convention. */
+int EVP_PKEY_derive(EVP_PKEY_CTX *ctx, uint8_t *key, size_t *out_key_len);
+
+/* EVP_PKEY_keygen_init initialises an |EVP_PKEY_CTX| for a key generation
+ * operation. It should be called before |EVP_PKEY_keygen|.
+ *
+ * It returns one on success or <= 0 on error. WARNING: this differs from the
+ * usual return value convention. */
+int EVP_PKEY_keygen_init(EVP_PKEY_CTX *ctx);
+
+/* EVP_PKEY_keygen performs a key generation operation using the values from
+ * |ctx| and sets |*ppkey| to a fresh |EVP_PKEY| containing the resulting key.
+ * It returns one on success or <= 0 on error. WARNING: this differs from the
+ * normal return value convention. */
+int EVP_PKEY_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY **ppkey);
+
+
+/* EVP_PKEY_CTX_ctrl operations.
+ *
+ * These values are passed as the |cmd| argument to
+ * EVP_PKEY_CTX_ctrl */
+
+/* Generic. */
+
+/* EVP_PKEY_CTX_set_signature_md sets |md| as the digest to be used in a
+ * signature operation. It returns one on success or otherwise on error. See
+ * the return values of |EVP_PKEY_CTX_ctrl| for details. */
+int EVP_PKEY_CTX_set_signature_md(EVP_PKEY_CTX *ctx, const EVP_MD *md);
+
+/* EVP_PKEY_CTX_get_signature_md sets |*out_md| to the digest to be used in a
+ * signature operation. It returns one on success or otherwise on error. See
+ * the return values of |EVP_PKEY_CTX_ctrl| for details. */
+int EVP_PKEY_CTX_get_signature_md(EVP_PKEY_CTX *ctx, const EVP_MD **out_md);
+
+/* EVP_PKEY_CTRL_DIGESTINIT is an internal value. It's called by
+ * EVP_DigestInit_ex to signal the |EVP_PKEY| that a digest operation is
+ * starting. */
+#define EVP_PKEY_CTRL_DIGESTINIT 3
+
+/* EVP_PKEY_CTRL_PEER_KEY is called with different values of |p1|:
+ *   0: Is called from |EVP_PKEY_derive_set_peer| and |p2| contains a peer key.
+ *      If the return value is <= 0, the key is rejected.
+ *   1: Is called at the end of |EVP_PKEY_derive_set_peer| and |p2| contains a
+ *      peer key. If the return value is <= 0, the key is rejected.
+ *   2: Is called with |p2| == NULL to test whether the peer's key was used.
+ *      (EC)DH always return one in this case.
+ *   3: Is called with |p2| == NULL to set whether the peer's key was used.
+ *      (EC)DH always return one in this case. This was only used for GOST. */
+#define EVP_PKEY_CTRL_PEER_KEY 4
+
+/* EVP_PKEY_CTRL_SET_MAC_KEY sets a MAC key. For example, this can be done an
+ * |EVP_PKEY_CTX| prior to calling |EVP_PKEY_keygen| in order to generate an
+ * HMAC |EVP_PKEY| with the given key. It returns one on success and zero on
+ * error. */
+#define EVP_PKEY_CTRL_SET_MAC_KEY 5
+
+/* EVP_PKEY_ALG_CTRL is the base value from which key-type specific ctrl
+ * commands are numbered. */
+#define EVP_PKEY_ALG_CTRL 0x1000
+
+
+/* RSA specific control functions. */
+
+/* EVP_PKEY_CTX_set_rsa_padding sets the padding type to use. It should be one
+ * of the |RSA_*_PADDING| values. Returns one on success or another value on
+ * error. See |EVP_PKEY_CTX_ctrl| for the other return values, which are
+ * non-standard. */
+int EVP_PKEY_CTX_set_rsa_padding(EVP_PKEY_CTX *ctx, int padding);
+
+/* EVP_PKEY_CTX_get_rsa_padding sets |*out_padding| to the current padding
+ * value, which is one of the |RSA_*_PADDING| values. Returns one on success or
+ * another value on error. See |EVP_PKEY_CTX_ctrl| for the other return values,
+ * which are non-standard. */
+int EVP_PKEY_CTX_get_rsa_padding(EVP_PKEY_CTX *ctx, int *out_padding);
+
+/* EVP_PKEY_CTX_set_rsa_pss_saltlen sets the length of the salt in a PSS-padded
+ * signature. A value of -1 cause the salt to be the same length as the digest
+ * in the signature. A value of -2 causes the salt to be the maximum length
+ * that will fit. Otherwise the value gives the size of the salt in bytes.
+ *
+ * Returns one on success or another value on error. See |EVP_PKEY_CTX_ctrl|
+ * for the other return values, which are non-standard. */
+int EVP_PKEY_CTX_set_rsa_pss_saltlen(EVP_PKEY_CTX *ctx, int salt_len);
+
+/* EVP_PKEY_CTX_get_rsa_pss_saltlen sets |*out_salt_len| to the salt length of
+ * a PSS-padded signature. See the documentation for
+ * |EVP_PKEY_CTX_set_rsa_pss_saltlen| for details of the special values that it
+ * can take.
+ *
+ * Returns one on success or another value on error. See |EVP_PKEY_CTX_ctrl|
+ * for the other return values, which are non-standard. */
+int EVP_PKEY_CTX_get_rsa_pss_saltlen(EVP_PKEY_CTX *ctx, int *out_salt_len);
+
+/* EVP_PKEY_CTX_set_rsa_keygen_bits sets the size of the desired RSA modulus,
+ * in bits, for key generation. Returns one on success or another value on
+ * error. See |EVP_PKEY_CTX_ctrl| for the other return values, which are
+ * non-standard. */
+int EVP_PKEY_CTX_set_rsa_keygen_bits(EVP_PKEY_CTX *ctx, int bits);
+
+/* EVP_PKEY_CTX_set_rsa_keygen_pubexp sets |e| as the public exponent for key
+ * generation. Returns one on success or another value on error. See
+ * |EVP_PKEY_CTX_ctrl| for the other return values, which are non-standard. */
+int EVP_PKEY_CTX_set_rsa_keygen_pubexp(EVP_PKEY_CTX *ctx, BIGNUM *e);
+
+/* EVP_PKEY_CTX_set_rsa_oaep_md sets |md| as the digest used in OAEP padding.
+ * Returns one on success or another value on error. See |EVP_PKEY_CTX_ctrl|
+ * for the other return values, which are non-standard. */
+int EVP_PKEY_CTX_set_rsa_oaep_md(EVP_PKEY_CTX *ctx, const EVP_MD *md);
+
+/* EVP_PKEY_CTX_get_rsa_oaep_md sets |*out_md| to the digest function used in
+ * OAEP padding. Returns one on success or another value on error. See
+ * |EVP_PKEY_CTX_ctrl| for the other return values, which are non-standard. */
+int EVP_PKEY_CTX_get_rsa_oaep_md(EVP_PKEY_CTX *ctx, const EVP_MD **out_md);
+
+/* EVP_PKEY_CTX_set_rsa_mgf1_md sets |md| as the digest used in MGF1. Returns
+ * one on success or another value on error. See |EVP_PKEY_CTX_ctrl| for the
+ * other return values, which are non-standard. */
+int EVP_PKEY_CTX_set_rsa_mgf1_md(EVP_PKEY_CTX *ctx, const EVP_MD *md);
+
+/* EVP_PKEY_CTX_get_rsa_mgf1_md sets |*out_md| to the digest function used in
+ * MGF1. Returns one on success or another value on error. See
+ * |EVP_PKEY_CTX_ctrl| for the other return values, which are non-standard. */
+int EVP_PKEY_CTX_get_rsa_mgf1_md(EVP_PKEY_CTX *ctx, const EVP_MD **out_md);
+
+/* EVP_PKEY_CTX_set0_rsa_oaep_label sets |label_len| bytes from |label| as the
+ * label used in OAEP. DANGER: this call takes ownership of |label| and will
+ * call |free| on it when |ctx| is destroyed.
+ *
+ * Returns one on success or another value on error. See |EVP_PKEY_CTX_ctrl|
+ * for the other return values, which are non-standard. */
+int EVP_PKEY_CTX_set0_rsa_oaep_label(EVP_PKEY_CTX *ctx, const uint8_t *label,
+                                     size_t label_len);
+
+/* EVP_PKEY_CTX_get0_rsa_oaep_label sets |*out_label| to point to the internal
+ * buffer containing the OAEP label (which may be NULL) and returns the length
+ * of the label or a negative value on error. */
+int EVP_PKEY_CTX_get0_rsa_oaep_label(EVP_PKEY_CTX *ctx,
+                                     const uint8_t **out_label);
+
+
+/* EC specific */
+
+#define EVP_PKEY_CTRL_EC_PARAMGEN_CURVE_NID		(EVP_PKEY_ALG_CTRL + 1)
+#define EVP_PKEY_CTRL_EC_PARAM_ENC			(EVP_PKEY_ALG_CTRL + 2)
+#define EVP_PKEY_CTRL_EC_ECDH_COFACTOR			(EVP_PKEY_ALG_CTRL + 3)
+#define EVP_PKEY_CTRL_EC_KDF_TYPE			(EVP_PKEY_ALG_CTRL + 4)
+#define EVP_PKEY_CTRL_EC_KDF_MD				(EVP_PKEY_ALG_CTRL + 5)
+#define EVP_PKEY_CTRL_GET_EC_KDF_MD			(EVP_PKEY_ALG_CTRL + 6)
+#define EVP_PKEY_CTRL_EC_KDF_OUTLEN			(EVP_PKEY_ALG_CTRL + 7)
+#define EVP_PKEY_CTRL_GET_EC_KDF_OUTLEN			(EVP_PKEY_ALG_CTRL + 8)
+#define EVP_PKEY_CTRL_EC_KDF_UKM			(EVP_PKEY_ALG_CTRL + 9)
+#define EVP_PKEY_CTRL_GET_EC_KDF_UKM			(EVP_PKEY_ALG_CTRL + 10)
+
+#define EVP_PKEY_ECDH_KDF_NONE 1
+#define EVP_PKEY_ECDH_KDF_X9_62 2
+
+
+/* PKEY ctrl commands.
+ *
+ * These values are passed as the |op| argument to
+ * EVP_PKEY_ASN1_METHOD.pkey_ctrl. */
+
+/* ASN1_PKEY_CTRL_DEFAULT_MD_NID expects |arg2| to be an |int*| and sets the
+ * pointed at int to be the NID of the default hash function used in
+ * signing. */
+#define ASN1_PKEY_CTRL_DEFAULT_MD_NID 0x3
+
+
+/* Private functions */
+
+/* OpenSSL_add_all_algorithms does nothing. */
+void OpenSSL_add_all_algorithms();
+
+/* EVP_cleanup does nothing. */
+void EVP_cleanup();
+
+/* EVP_PKEY_asn1_find returns the ASN.1 method table for the given |nid|, which
+ * should be one of the |EVP_PKEY_*| values. It returns NULL if |nid| is
+ * unknown. */
+const EVP_PKEY_ASN1_METHOD *EVP_PKEY_asn1_find(ENGINE **pengine, int nid);
+
+/* TODO(fork): move to PEM? */
+const EVP_PKEY_ASN1_METHOD *EVP_PKEY_asn1_find_str(ENGINE **pengine,
+                                                   const char *name,
+                                                   size_t len);
+
+struct evp_pkey_st {
+  int references;
+
+  /* type contains one of the EVP_PKEY_* values or NID_undef and determines
+   * which element (if any) of the |pkey| union is valid. */
+  int type;
+
+  /* TODO(fork): document */
+  int save_type;
+
+  union {
+    char *ptr;
+    struct rsa_st *rsa; /* RSA */
+    struct dsa_st *dsa; /* DSA */
+    struct dh_st *dh; /* DH */
+    struct ec_key_st *ec; /* ECC */
+  } pkey;
+
+  ENGINE *engine;
+
+  /* TODO(fork): document */
+  int save_parameters;
+  /* ameth contains a pointer to a method table that contains many ASN.1
+   * methods for the key type. */
+  const EVP_PKEY_ASN1_METHOD *ameth;
+
+  /* TODO(fork): document; */
+  STACK_OF(X509_ATTRIBUTE) * attributes; /* [ 0 ] */
+} /* EVP_PKEY */;
+
+
+#if defined(__cplusplus)
+}  /* extern C */
+#endif
+
+#define EVP_F_rsa_item_verify 100
+#define EVP_F_do_sigver_init 101
+#define EVP_F_eckey_priv_decode 102
+#define EVP_F_pkey_ec_sign 103
+#define EVP_F_EVP_PKEY_sign_init 104
+#define EVP_F_d2i_PrivateKey 105
+#define EVP_F_rsa_priv_encode 106
+#define EVP_F_rsa_mgf1_to_md 107
+#define EVP_F_EVP_PKEY_get1_DH 108
+#define EVP_F_EVP_PKEY_sign 109
+#define EVP_F_old_ec_priv_decode 110
+#define EVP_F_EVP_PKEY_get1_RSA 111
+#define EVP_F_pkey_ec_ctrl 112
+#define EVP_F_evp_pkey_ctx_new 113
+#define EVP_F_EVP_PKEY_verify 114
+#define EVP_F_EVP_PKEY_encrypt 115
+#define EVP_F_EVP_PKEY_keygen 116
+#define EVP_F_eckey_type2param 117
+#define EVP_F_eckey_priv_encode 118
+#define EVP_F_do_EC_KEY_print 119
+#define EVP_F_pkey_ec_keygen 120
+#define EVP_F_EVP_PKEY_encrypt_init 121
+#define EVP_F_pkey_rsa_ctrl 122
+#define EVP_F_rsa_priv_decode 123
+#define EVP_F_rsa_pss_to_ctx 124
+#define EVP_F_EVP_PKEY_get1_EC_KEY 125
+#define EVP_F_EVP_PKEY_verify_init 126
+#define EVP_F_EVP_PKEY_derive_init 127
+#define EVP_F_eckey_param2type 128
+#define EVP_F_eckey_pub_decode 129
+#define EVP_F_d2i_AutoPrivateKey 130
+#define EVP_F_eckey_param_decode 131
+#define EVP_F_EVP_PKEY_new 132
+#define EVP_F_pkey_ec_derive 133
+#define EVP_F_pkey_ec_paramgen 134
+#define EVP_F_EVP_PKEY_CTX_ctrl 135
+#define EVP_F_EVP_PKEY_decrypt_init 136
+#define EVP_F_EVP_PKEY_decrypt 137
+#define EVP_F_EVP_PKEY_copy_parameters 138
+#define EVP_F_EVP_PKEY_set_type 139
+#define EVP_F_EVP_PKEY_derive 140
+#define EVP_F_EVP_PKEY_keygen_init 141
+#define EVP_F_do_rsa_print 142
+#define EVP_F_old_rsa_priv_decode 143
+#define EVP_F_rsa_algor_to_md 144
+#define EVP_F_eckey_pub_encode 145
+#define EVP_F_EVP_PKEY_derive_set_peer 146
+#define EVP_F_pkey_rsa_sign 147
+#define EVP_F_check_padding_md 148
+#define EVP_F_i2d_PublicKey 149
+#define EVP_F_rsa_pub_decode 150
+#define EVP_F_EVP_PKEY_get1_DSA 151
+#define EVP_R_UNSUPPORTED_PUBLIC_KEY_TYPE 100
+#define EVP_R_UNSUPPORTED_SIGNATURE_TYPE 101
+#define EVP_R_INVALID_DIGEST_TYPE 102
+#define EVP_R_EXPECTING_A_DH_KEY 103
+#define EVP_R_OPERATON_NOT_INITIALIZED 104
+#define EVP_R_MISSING_PARAMETERS 105
+#define EVP_R_NO_DEFAULT_DIGEST 106
+#define EVP_R_UNKNOWN_DIGEST 107
+#define EVP_R_KEYS_NOT_SET 108
+#define EVP_R_X931_UNSUPPORTED 109
+#define EVP_R_DIGEST_DOES_NOT_MATCH 110
+#define EVP_R_DIFFERENT_PARAMETERS 111
+#define EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE 112
+#define EVP_R_DIFFERENT_KEY_TYPES 113
+#define EVP_R_NO_PARAMETERS_SET 114
+#define EVP_R_NO_NID_FOR_CURVE 115
+#define EVP_R_NO_OPERATION_SET 116
+#define EVP_R_UNSUPPORTED_ALGORITHM 117
+#define EVP_R_EXPECTING_AN_DSA_KEY 118
+#define EVP_R_UNKNOWN_MASK_DIGEST 119
+#define EVP_R_INVALID_SALT_LENGTH 120
+#define EVP_R_BUFFER_TOO_SMALL 121
+#define EVP_R_INVALID_PADDING_MODE 122
+#define EVP_R_INVALID_MGF1_MD 123
+#define EVP_R_SHARED_INFO_ERROR 124
+#define EVP_R_INVALID_KEYBITS 125
+#define EVP_R_PEER_KEY_ERROR 126
+#define EVP_R_EXPECTING_A_DSA_KEY 127
+#define EVP_R_UNSUPPORTED_MASK_ALGORITHM 128
+#define EVP_R_EXPECTING_AN_EC_KEY_KEY 129
+#define EVP_R_INVALID_TRAILER 130
+#define EVP_R_INVALID_DIGEST_LENGTH 131
+#define EVP_R_COMMAND_NOT_SUPPORTED 132
+#define EVP_R_EXPLICIT_EC_PARAMETERS_NOT_SUPPORTED 133
+#define EVP_R_ILLEGAL_OR_UNSUPPORTED_PADDING_MODE 134
+#define EVP_R_NO_MDC2_SUPPORT 135
+#define EVP_R_INVALID_CURVE 136
+#define EVP_R_NO_KEY_SET 137
+#define EVP_R_INVALID_PSS_PARAMETERS 138
+#define EVP_R_KDF_PARAMETER_ERROR 139
+#define EVP_R_UNSUPPORTED_MASK_PARAMETER 140
+#define EVP_R_EXPECTING_AN_RSA_KEY 141
+#define EVP_R_INVALID_OPERATION 142
+#define EVP_R_DECODE_ERROR 143
+#define EVP_R_INVALID_PSS_SALTLEN 144
+#define EVP_R_UNKNOWN_PUBLIC_KEY_TYPE 145
+
+#endif  /* OPENSSL_HEADER_EVP_H */
diff --git a/crypto/evp/evp_ctx.c b/crypto/evp/evp_ctx.c
new file mode 100644
index 0000000..5c3755a
--- /dev/null
+++ b/crypto/evp/evp_ctx.c
@@ -0,0 +1,548 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.] */
+
+#include <openssl/evp.h>
+
+#include <stdio.h>
+
+#include <openssl/err.h>
+#include <openssl/mem.h>
+#include <openssl/obj.h>
+
+#include "internal.h"
+
+
+extern const EVP_PKEY_METHOD rsa_pkey_meth;
+extern const EVP_PKEY_METHOD hmac_pkey_meth;
+extern const EVP_PKEY_METHOD ec_pkey_meth;
+
+static const EVP_PKEY_METHOD *evp_methods[] = {
+  &rsa_pkey_meth,
+  &hmac_pkey_meth,
+  &ec_pkey_meth,
+};
+
+static const EVP_PKEY_METHOD *evp_pkey_meth_find(int type) {
+  unsigned i;
+
+  for (i = 0; i < sizeof(evp_methods)/sizeof(EVP_PKEY_METHOD*); i++) {
+    if (evp_methods[i]->pkey_id == type) {
+      return evp_methods[i];
+    }
+  }
+
+  return NULL;
+}
+
+static EVP_PKEY_CTX *evp_pkey_ctx_new(EVP_PKEY *pkey, ENGINE *e, int id) {
+  EVP_PKEY_CTX *ret;
+  const EVP_PKEY_METHOD *pmeth;
+
+  if (id == -1) {
+    if (!pkey || !pkey->ameth) {
+      return NULL;
+    }
+    id = pkey->ameth->pkey_id;
+  }
+
+  pmeth = evp_pkey_meth_find(id);
+
+  if (pmeth == NULL) {
+    OPENSSL_PUT_ERROR(EVP, evp_pkey_ctx_new, EVP_R_UNSUPPORTED_ALGORITHM);
+    const char *name = OBJ_nid2sn(id);
+    ERR_add_error_dataf("algorithm %d (%s)", id, name);
+    return NULL;
+  }
+
+  ret = OPENSSL_malloc(sizeof(EVP_PKEY_CTX));
+  if (!ret) {
+    OPENSSL_PUT_ERROR(EVP, evp_pkey_ctx_new, ERR_R_MALLOC_FAILURE);
+    return NULL;
+  }
+  memset(ret, 0, sizeof(EVP_PKEY_CTX));
+
+  ret->engine = e;
+  ret->pmeth = pmeth;
+  ret->operation = EVP_PKEY_OP_UNDEFINED;
+
+  if (pkey) {
+    ret->pkey = pkey;
+    CRYPTO_add(&pkey->references, 1, CRYPTO_LOCK_EVP_PKEY);
+  }
+
+  if (pmeth->init) {
+    if (pmeth->init(ret) <= 0) {
+      EVP_PKEY_CTX_free(ret);
+      return NULL;
+    }
+  }
+
+  return ret;
+}
+
+EVP_PKEY_CTX *EVP_PKEY_CTX_new(EVP_PKEY *pkey, ENGINE *e) {
+  return evp_pkey_ctx_new(pkey, e, -1);
+}
+
+EVP_PKEY_CTX *EVP_PKEY_CTX_new_id(int id, ENGINE *e) {
+  return evp_pkey_ctx_new(NULL, e, id);
+}
+
+void EVP_PKEY_CTX_free(EVP_PKEY_CTX *ctx) {
+  if (ctx == NULL) {
+    return;
+  }
+  if (ctx->pmeth && ctx->pmeth->cleanup) {
+    ctx->pmeth->cleanup(ctx);
+  }
+  if (ctx->pkey) {
+    EVP_PKEY_free(ctx->pkey);
+  }
+  if (ctx->peerkey) {
+    EVP_PKEY_free(ctx->peerkey);
+  }
+  OPENSSL_free(ctx);
+}
+
+EVP_PKEY_CTX *EVP_PKEY_CTX_dup(EVP_PKEY_CTX *pctx) {
+  EVP_PKEY_CTX *rctx;
+
+  if (!pctx->pmeth || !pctx->pmeth->copy) {
+    return NULL;
+  }
+
+  rctx = OPENSSL_malloc(sizeof(EVP_PKEY_CTX));
+  if (!rctx) {
+    return NULL;
+  }
+
+  memset(rctx, 0, sizeof(EVP_PKEY_CTX));
+
+  rctx->pmeth = pctx->pmeth;
+  rctx->engine = pctx->engine;
+  rctx->operation = pctx->operation;
+
+  if (pctx->pkey) {
+    CRYPTO_add(&pctx->pkey->references, 1, CRYPTO_LOCK_EVP_PKEY);
+  }
+  rctx->pkey = pctx->pkey;
+
+  if (pctx->peerkey) {
+    CRYPTO_add(&pctx->peerkey->references, 1, CRYPTO_LOCK_EVP_PKEY);
+  }
+  rctx->peerkey = pctx->peerkey;
+
+  if (pctx->pmeth->copy(rctx, pctx) > 0) {
+    return rctx;
+  }
+
+  EVP_PKEY_CTX_free(rctx);
+  return NULL;
+}
+
+EVP_PKEY *EVP_PKEY_CTX_get0_pkey(EVP_PKEY_CTX *ctx) { return ctx->pkey; }
+
+void EVP_PKEY_CTX_set_app_data(EVP_PKEY_CTX *ctx, void *data) {
+  ctx->app_data = data;
+}
+
+void *EVP_PKEY_CTX_get_app_data(EVP_PKEY_CTX *ctx) { return ctx->app_data; }
+
+int EVP_PKEY_CTX_ctrl(EVP_PKEY_CTX *ctx, int keytype, int optype, int cmd,
+                      int p1, void *p2) {
+  int ret;
+  if (!ctx || !ctx->pmeth || !ctx->pmeth->ctrl) {
+    OPENSSL_PUT_ERROR(EVP, EVP_PKEY_CTX_ctrl, EVP_R_COMMAND_NOT_SUPPORTED);
+    return -2;
+  }
+  if (keytype != -1 && ctx->pmeth->pkey_id != keytype) {
+    return -1;
+  }
+
+  if (ctx->operation == EVP_PKEY_OP_UNDEFINED) {
+    OPENSSL_PUT_ERROR(EVP, EVP_PKEY_CTX_ctrl, EVP_R_NO_OPERATION_SET);
+    return -1;
+  }
+
+  if (optype != -1 && !(ctx->operation & optype)) {
+    OPENSSL_PUT_ERROR(EVP, EVP_PKEY_CTX_ctrl, EVP_R_INVALID_OPERATION);
+    return -1;
+  }
+
+  ret = ctx->pmeth->ctrl(ctx, cmd, p1, p2);
+
+  if (ret == -2) {
+    OPENSSL_PUT_ERROR(EVP, EVP_PKEY_CTX_ctrl, EVP_R_COMMAND_NOT_SUPPORTED);
+  }
+
+  return ret;
+}
+
+int EVP_PKEY_sign_init(EVP_PKEY_CTX *ctx) {
+  int ret;
+  if (!ctx || !ctx->pmeth || !ctx->pmeth->sign) {
+    OPENSSL_PUT_ERROR(EVP, EVP_PKEY_sign_init,
+                      EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+    return 0;
+  }
+
+  ctx->operation = EVP_PKEY_OP_SIGN;
+  if (!ctx->pmeth->sign_init) {
+    return 1;
+  }
+
+  ret = ctx->pmeth->sign_init(ctx);
+  /* TODO(fork): normalise the return value convention. */
+  if (ret <= 0) {
+    ctx->operation = EVP_PKEY_OP_UNDEFINED;
+    return 0;
+  }
+
+  return ret;
+}
+
+static int check_autoarg(const EVP_PKEY_CTX *ctx, const uint8_t *arg,
+                         size_t *arg_len) {
+  size_t size;
+
+  if (0 == (ctx->pmeth->flags & EVP_PKEY_FLAG_AUTOARGLEN)) {
+    return 1;
+  }
+
+  size = EVP_PKEY_size(ctx->pkey);
+  if (arg == NULL) {
+    *arg_len = size;
+    return 1;
+  }
+
+  if (*arg_len < size) {
+    return 0;
+  }
+
+  return 1;
+}
+
+int EVP_PKEY_sign(EVP_PKEY_CTX *ctx, uint8_t *sig, size_t *sig_len,
+                  const uint8_t *data, size_t data_len) {
+  if (!ctx || !ctx->pmeth || !ctx->pmeth->sign) {
+    OPENSSL_PUT_ERROR(EVP, EVP_PKEY_sign,
+                      EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+    return 0;
+  }
+  if (ctx->operation != EVP_PKEY_OP_SIGN) {
+    OPENSSL_PUT_ERROR(EVP, EVP_PKEY_sign, EVP_R_OPERATON_NOT_INITIALIZED);
+    return 0;
+  }
+  if (!check_autoarg(ctx, sig, sig_len)) {
+    OPENSSL_PUT_ERROR(EVP, EVP_PKEY_sign,
+                      EVP_R_BUFFER_TOO_SMALL);
+    return 0;
+  }
+  return ctx->pmeth->sign(ctx, sig, sig_len, data, data_len);
+}
+
+int EVP_PKEY_verify_init(EVP_PKEY_CTX *ctx) {
+  int ret;
+
+  if (!ctx || !ctx->pmeth || !ctx->pmeth->verify) {
+    OPENSSL_PUT_ERROR(EVP, EVP_PKEY_verify_init,
+                      EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+    return -2;
+  }
+  ctx->operation = EVP_PKEY_OP_VERIFY;
+  if (!ctx->pmeth->verify_init) {
+    return 1;
+  }
+  ret = ctx->pmeth->verify_init(ctx);
+  if (ret <= 0) {
+    ctx->operation = EVP_PKEY_OP_UNDEFINED;
+  }
+  return ret;
+}
+
+int EVP_PKEY_verify(EVP_PKEY_CTX *ctx, const uint8_t *sig, size_t sig_len,
+                    const uint8_t *data, size_t data_len) {
+  if (!ctx || !ctx->pmeth || !ctx->pmeth->verify) {
+    OPENSSL_PUT_ERROR(EVP, EVP_PKEY_verify,
+                      EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+    return -2;
+  }
+  if (ctx->operation != EVP_PKEY_OP_VERIFY) {
+    OPENSSL_PUT_ERROR(EVP, EVP_PKEY_verify, EVP_R_OPERATON_NOT_INITIALIZED);
+    return -1;
+  }
+  return ctx->pmeth->verify(ctx, sig, sig_len, data, data_len);
+}
+
+int EVP_PKEY_encrypt_init(EVP_PKEY_CTX *ctx) {
+  int ret;
+  if (!ctx || !ctx->pmeth || !ctx->pmeth->encrypt) {
+    OPENSSL_PUT_ERROR(EVP, EVP_PKEY_encrypt_init,
+                      EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+    return -2;
+  }
+  ctx->operation = EVP_PKEY_OP_ENCRYPT;
+  if (!ctx->pmeth->encrypt_init) {
+    return 1;
+  }
+  ret = ctx->pmeth->encrypt_init(ctx);
+  if (ret <= 0) {
+    ctx->operation = EVP_PKEY_OP_UNDEFINED;
+  }
+  return ret;
+}
+
+int EVP_PKEY_encrypt(EVP_PKEY_CTX *ctx, uint8_t *out, size_t *outlen,
+                     const uint8_t *in, size_t inlen) {
+  if (!ctx || !ctx->pmeth || !ctx->pmeth->encrypt) {
+    OPENSSL_PUT_ERROR(EVP, EVP_PKEY_encrypt,
+                      EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+    return -2;
+  }
+  if (ctx->operation != EVP_PKEY_OP_ENCRYPT) {
+    OPENSSL_PUT_ERROR(EVP, EVP_PKEY_encrypt, EVP_R_OPERATON_NOT_INITIALIZED);
+    return -1;
+  }
+  if (!check_autoarg(ctx, out, outlen)) {
+    OPENSSL_PUT_ERROR(EVP, EVP_PKEY_encrypt, EVP_R_BUFFER_TOO_SMALL);
+    return 0;
+  }
+  return ctx->pmeth->encrypt(ctx, out, outlen, in, inlen);
+}
+
+int EVP_PKEY_decrypt_init(EVP_PKEY_CTX *ctx) {
+  int ret;
+
+  if (!ctx || !ctx->pmeth || !ctx->pmeth->decrypt) {
+    OPENSSL_PUT_ERROR(EVP, EVP_PKEY_decrypt_init,
+                      EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+    return -2;
+  }
+  ctx->operation = EVP_PKEY_OP_DECRYPT;
+  if (!ctx->pmeth->decrypt_init) {
+    return 1;
+  }
+  ret = ctx->pmeth->decrypt_init(ctx);
+  if (ret <= 0) {
+    ctx->operation = EVP_PKEY_OP_UNDEFINED;
+  }
+  return ret;
+}
+
+int EVP_PKEY_decrypt(EVP_PKEY_CTX *ctx, uint8_t *out, size_t *outlen,
+                     const uint8_t *in, size_t inlen) {
+  if (!ctx || !ctx->pmeth || !ctx->pmeth->decrypt) {
+    OPENSSL_PUT_ERROR(EVP, EVP_PKEY_decrypt,
+                      EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+    return -2;
+  }
+  if (ctx->operation != EVP_PKEY_OP_DECRYPT) {
+    OPENSSL_PUT_ERROR(EVP, EVP_PKEY_decrypt, EVP_R_OPERATON_NOT_INITIALIZED);
+    return -1;
+  }
+  if (!check_autoarg(ctx, out, outlen)) {
+    OPENSSL_PUT_ERROR(EVP, EVP_PKEY_decrypt, EVP_R_BUFFER_TOO_SMALL);
+    return 0;
+  }
+  return ctx->pmeth->decrypt(ctx, out, outlen, in, inlen);
+}
+
+int EVP_PKEY_derive_init(EVP_PKEY_CTX *ctx) {
+  int ret;
+  if (!ctx || !ctx->pmeth || !ctx->pmeth->derive) {
+    OPENSSL_PUT_ERROR(EVP, EVP_PKEY_derive_init,
+                      EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+    return -2;
+  }
+  ctx->operation = EVP_PKEY_OP_DERIVE;
+  if (!ctx->pmeth->derive_init) {
+    return 1;
+  }
+  ret = ctx->pmeth->derive_init(ctx);
+  if (ret <= 0) {
+    ctx->operation = EVP_PKEY_OP_UNDEFINED;
+  }
+  return ret;
+}
+
+int EVP_PKEY_derive_set_peer(EVP_PKEY_CTX *ctx, EVP_PKEY *peer) {
+  int ret;
+  if (!ctx || !ctx->pmeth ||
+      !(ctx->pmeth->derive || ctx->pmeth->encrypt || ctx->pmeth->decrypt) ||
+      !ctx->pmeth->ctrl) {
+    OPENSSL_PUT_ERROR(EVP, EVP_PKEY_derive_set_peer,
+                      EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+    return -2;
+  }
+  if (ctx->operation != EVP_PKEY_OP_DERIVE &&
+      ctx->operation != EVP_PKEY_OP_ENCRYPT &&
+      ctx->operation != EVP_PKEY_OP_DECRYPT) {
+    OPENSSL_PUT_ERROR(EVP, EVP_PKEY_derive_set_peer,
+                      EVP_R_OPERATON_NOT_INITIALIZED);
+    return -1;
+  }
+
+  ret = ctx->pmeth->ctrl(ctx, EVP_PKEY_CTRL_PEER_KEY, 0, peer);
+
+  if (ret <= 0) {
+    return ret;
+  }
+
+  if (ret == 2) {
+    return 1;
+  }
+
+  if (!ctx->pkey) {
+    OPENSSL_PUT_ERROR(EVP, EVP_PKEY_derive_set_peer, EVP_R_NO_KEY_SET);
+    return -1;
+  }
+
+  if (ctx->pkey->type != peer->type) {
+    OPENSSL_PUT_ERROR(EVP, EVP_PKEY_derive_set_peer, EVP_R_DIFFERENT_KEY_TYPES);
+    return -1;
+  }
+
+  /* ran@cryptocom.ru: For clarity.  The error is if parameters in peer are
+   * present (!missing) but don't match.  EVP_PKEY_cmp_parameters may return
+   * 1 (match), 0 (don't match) and -2 (comparison is not defined).  -1
+   * (different key types) is impossible here because it is checked earlier.
+   * -2 is OK for us here, as well as 1, so we can check for 0 only. */
+  if (!EVP_PKEY_missing_parameters(peer) &&
+      !EVP_PKEY_cmp_parameters(ctx->pkey, peer)) {
+    OPENSSL_PUT_ERROR(EVP, EVP_PKEY_derive_set_peer,
+                      EVP_R_DIFFERENT_PARAMETERS);
+    return -1;
+  }
+
+  if (ctx->peerkey) {
+    EVP_PKEY_free(ctx->peerkey);
+  }
+  ctx->peerkey = peer;
+
+  ret = ctx->pmeth->ctrl(ctx, EVP_PKEY_CTRL_PEER_KEY, 1, peer);
+
+  if (ret <= 0) {
+    ctx->peerkey = NULL;
+    return ret;
+  }
+
+  CRYPTO_add(&peer->references, 1, CRYPTO_LOCK_EVP_PKEY);
+  return 1;
+}
+
+int EVP_PKEY_derive(EVP_PKEY_CTX *ctx, uint8_t *key, size_t *out_key_len) {
+  if (!ctx || !ctx->pmeth || !ctx->pmeth->derive) {
+    OPENSSL_PUT_ERROR(EVP, EVP_PKEY_derive,
+                      EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+    return -2;
+  }
+  if (ctx->operation != EVP_PKEY_OP_DERIVE) {
+    OPENSSL_PUT_ERROR(EVP, EVP_PKEY_derive, EVP_R_OPERATON_NOT_INITIALIZED);
+    return -1;
+  }
+  if (!check_autoarg(ctx, key, out_key_len)) {
+    OPENSSL_PUT_ERROR(EVP, EVP_PKEY_derive, EVP_R_BUFFER_TOO_SMALL);
+    return 0;
+  }
+  return ctx->pmeth->derive(ctx, key, out_key_len);
+}
+
+int EVP_PKEY_keygen_init(EVP_PKEY_CTX *ctx) {
+  int ret;
+  if (!ctx || !ctx->pmeth || !ctx->pmeth->keygen) {
+    OPENSSL_PUT_ERROR(EVP, EVP_PKEY_keygen_init,
+                      EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+    return -2;
+  }
+  ctx->operation = EVP_PKEY_OP_KEYGEN;
+  if (!ctx->pmeth->keygen_init) {
+    return 1;
+  }
+  ret = ctx->pmeth->keygen_init(ctx);
+  if (ret <= 0) {
+    ctx->operation = EVP_PKEY_OP_UNDEFINED;
+  }
+  return ret;
+}
+
+int EVP_PKEY_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY **ppkey) {
+  int ret;
+
+  if (!ctx || !ctx->pmeth || !ctx->pmeth->keygen) {
+    OPENSSL_PUT_ERROR(EVP, EVP_PKEY_keygen,
+                      EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+    return -2;
+  }
+  if (ctx->operation != EVP_PKEY_OP_KEYGEN) {
+    OPENSSL_PUT_ERROR(EVP, EVP_PKEY_keygen, EVP_R_OPERATON_NOT_INITIALIZED);
+    return -1;
+  }
+
+  if (!ppkey) {
+    return -1;
+  }
+
+  if (!*ppkey) {
+    *ppkey = EVP_PKEY_new();
+  }
+
+  ret = ctx->pmeth->keygen(ctx, *ppkey);
+  if (ret <= 0) {
+    EVP_PKEY_free(*ppkey);
+    *ppkey = NULL;
+  }
+  return ret;
+}
diff --git a/crypto/evp/evp_error.c b/crypto/evp/evp_error.c
new file mode 100644
index 0000000..0b4d2f2
--- /dev/null
+++ b/crypto/evp/evp_error.c
@@ -0,0 +1,119 @@
+/* Copyright (c) 2014, 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/err.h>
+
+#include "evp.h"
+
+const ERR_STRING_DATA EVP_error_string_data[] = {
+  {ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_PKEY_CTX_ctrl, 0), "EVP_PKEY_CTX_ctrl"},
+  {ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_PKEY_copy_parameters, 0), "EVP_PKEY_copy_parameters"},
+  {ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_PKEY_decrypt, 0), "EVP_PKEY_decrypt"},
+  {ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_PKEY_decrypt_init, 0), "EVP_PKEY_decrypt_init"},
+  {ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_PKEY_derive, 0), "EVP_PKEY_derive"},
+  {ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_PKEY_derive_init, 0), "EVP_PKEY_derive_init"},
+  {ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_PKEY_derive_set_peer, 0), "EVP_PKEY_derive_set_peer"},
+  {ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_PKEY_encrypt, 0), "EVP_PKEY_encrypt"},
+  {ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_PKEY_encrypt_init, 0), "EVP_PKEY_encrypt_init"},
+  {ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_PKEY_get1_DH, 0), "EVP_PKEY_get1_DH"},
+  {ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_PKEY_get1_DSA, 0), "EVP_PKEY_get1_DSA"},
+  {ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_PKEY_get1_EC_KEY, 0), "EVP_PKEY_get1_EC_KEY"},
+  {ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_PKEY_get1_RSA, 0), "EVP_PKEY_get1_RSA"},
+  {ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_PKEY_keygen, 0), "EVP_PKEY_keygen"},
+  {ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_PKEY_keygen_init, 0), "EVP_PKEY_keygen_init"},
+  {ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_PKEY_new, 0), "EVP_PKEY_new"},
+  {ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_PKEY_set_type, 0), "EVP_PKEY_set_type"},
+  {ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_PKEY_sign, 0), "EVP_PKEY_sign"},
+  {ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_PKEY_sign_init, 0), "EVP_PKEY_sign_init"},
+  {ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_PKEY_verify, 0), "EVP_PKEY_verify"},
+  {ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_PKEY_verify_init, 0), "EVP_PKEY_verify_init"},
+  {ERR_PACK(ERR_LIB_EVP, EVP_F_check_padding_md, 0), "check_padding_md"},
+  {ERR_PACK(ERR_LIB_EVP, EVP_F_d2i_AutoPrivateKey, 0), "d2i_AutoPrivateKey"},
+  {ERR_PACK(ERR_LIB_EVP, EVP_F_d2i_PrivateKey, 0), "d2i_PrivateKey"},
+  {ERR_PACK(ERR_LIB_EVP, EVP_F_do_EC_KEY_print, 0), "do_EC_KEY_print"},
+  {ERR_PACK(ERR_LIB_EVP, EVP_F_do_rsa_print, 0), "do_rsa_print"},
+  {ERR_PACK(ERR_LIB_EVP, EVP_F_do_sigver_init, 0), "do_sigver_init"},
+  {ERR_PACK(ERR_LIB_EVP, EVP_F_eckey_param2type, 0), "eckey_param2type"},
+  {ERR_PACK(ERR_LIB_EVP, EVP_F_eckey_param_decode, 0), "eckey_param_decode"},
+  {ERR_PACK(ERR_LIB_EVP, EVP_F_eckey_priv_decode, 0), "eckey_priv_decode"},
+  {ERR_PACK(ERR_LIB_EVP, EVP_F_eckey_priv_encode, 0), "eckey_priv_encode"},
+  {ERR_PACK(ERR_LIB_EVP, EVP_F_eckey_pub_decode, 0), "eckey_pub_decode"},
+  {ERR_PACK(ERR_LIB_EVP, EVP_F_eckey_pub_encode, 0), "eckey_pub_encode"},
+  {ERR_PACK(ERR_LIB_EVP, EVP_F_eckey_type2param, 0), "eckey_type2param"},
+  {ERR_PACK(ERR_LIB_EVP, EVP_F_evp_pkey_ctx_new, 0), "evp_pkey_ctx_new"},
+  {ERR_PACK(ERR_LIB_EVP, EVP_F_i2d_PublicKey, 0), "i2d_PublicKey"},
+  {ERR_PACK(ERR_LIB_EVP, EVP_F_old_ec_priv_decode, 0), "old_ec_priv_decode"},
+  {ERR_PACK(ERR_LIB_EVP, EVP_F_old_rsa_priv_decode, 0), "old_rsa_priv_decode"},
+  {ERR_PACK(ERR_LIB_EVP, EVP_F_pkey_ec_ctrl, 0), "pkey_ec_ctrl"},
+  {ERR_PACK(ERR_LIB_EVP, EVP_F_pkey_ec_derive, 0), "pkey_ec_derive"},
+  {ERR_PACK(ERR_LIB_EVP, EVP_F_pkey_ec_keygen, 0), "pkey_ec_keygen"},
+  {ERR_PACK(ERR_LIB_EVP, EVP_F_pkey_ec_paramgen, 0), "pkey_ec_paramgen"},
+  {ERR_PACK(ERR_LIB_EVP, EVP_F_pkey_ec_sign, 0), "pkey_ec_sign"},
+  {ERR_PACK(ERR_LIB_EVP, EVP_F_pkey_rsa_ctrl, 0), "pkey_rsa_ctrl"},
+  {ERR_PACK(ERR_LIB_EVP, EVP_F_pkey_rsa_sign, 0), "pkey_rsa_sign"},
+  {ERR_PACK(ERR_LIB_EVP, EVP_F_rsa_algor_to_md, 0), "rsa_algor_to_md"},
+  {ERR_PACK(ERR_LIB_EVP, EVP_F_rsa_item_verify, 0), "rsa_item_verify"},
+  {ERR_PACK(ERR_LIB_EVP, EVP_F_rsa_mgf1_to_md, 0), "rsa_mgf1_to_md"},
+  {ERR_PACK(ERR_LIB_EVP, EVP_F_rsa_priv_decode, 0), "rsa_priv_decode"},
+  {ERR_PACK(ERR_LIB_EVP, EVP_F_rsa_priv_encode, 0), "rsa_priv_encode"},
+  {ERR_PACK(ERR_LIB_EVP, EVP_F_rsa_pss_to_ctx, 0), "rsa_pss_to_ctx"},
+  {ERR_PACK(ERR_LIB_EVP, EVP_F_rsa_pub_decode, 0), "rsa_pub_decode"},
+  {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_BUFFER_TOO_SMALL), "BUFFER_TOO_SMALL"},
+  {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_COMMAND_NOT_SUPPORTED), "COMMAND_NOT_SUPPORTED"},
+  {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_DECODE_ERROR), "DECODE_ERROR"},
+  {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_DIFFERENT_KEY_TYPES), "DIFFERENT_KEY_TYPES"},
+  {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_DIFFERENT_PARAMETERS), "DIFFERENT_PARAMETERS"},
+  {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_DIGEST_DOES_NOT_MATCH), "DIGEST_DOES_NOT_MATCH"},
+  {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_EXPECTING_AN_DSA_KEY), "EXPECTING_AN_DSA_KEY"},
+  {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_EXPECTING_AN_EC_KEY_KEY), "EXPECTING_AN_EC_KEY_KEY"},
+  {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_EXPECTING_AN_RSA_KEY), "EXPECTING_AN_RSA_KEY"},
+  {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_EXPECTING_A_DH_KEY), "EXPECTING_A_DH_KEY"},
+  {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_EXPECTING_A_DSA_KEY), "EXPECTING_A_DSA_KEY"},
+  {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_EXPLICIT_EC_PARAMETERS_NOT_SUPPORTED), "EXPLICIT_EC_PARAMETERS_NOT_SUPPORTED"},
+  {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_ILLEGAL_OR_UNSUPPORTED_PADDING_MODE), "ILLEGAL_OR_UNSUPPORTED_PADDING_MODE"},
+  {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_INVALID_CURVE), "INVALID_CURVE"},
+  {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_INVALID_DIGEST_LENGTH), "INVALID_DIGEST_LENGTH"},
+  {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_INVALID_DIGEST_TYPE), "INVALID_DIGEST_TYPE"},
+  {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_INVALID_KEYBITS), "INVALID_KEYBITS"},
+  {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_INVALID_MGF1_MD), "INVALID_MGF1_MD"},
+  {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_INVALID_OPERATION), "INVALID_OPERATION"},
+  {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_INVALID_PADDING_MODE), "INVALID_PADDING_MODE"},
+  {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_INVALID_PSS_PARAMETERS), "INVALID_PSS_PARAMETERS"},
+  {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_INVALID_PSS_SALTLEN), "INVALID_PSS_SALTLEN"},
+  {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_INVALID_SALT_LENGTH), "INVALID_SALT_LENGTH"},
+  {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_INVALID_TRAILER), "INVALID_TRAILER"},
+  {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_KDF_PARAMETER_ERROR), "KDF_PARAMETER_ERROR"},
+  {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_KEYS_NOT_SET), "KEYS_NOT_SET"},
+  {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_MISSING_PARAMETERS), "MISSING_PARAMETERS"},
+  {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_NO_DEFAULT_DIGEST), "NO_DEFAULT_DIGEST"},
+  {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_NO_KEY_SET), "NO_KEY_SET"},
+  {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_NO_MDC2_SUPPORT), "NO_MDC2_SUPPORT"},
+  {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_NO_NID_FOR_CURVE), "NO_NID_FOR_CURVE"},
+  {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_NO_OPERATION_SET), "NO_OPERATION_SET"},
+  {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_NO_PARAMETERS_SET), "NO_PARAMETERS_SET"},
+  {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE), "OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE"},
+  {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_OPERATON_NOT_INITIALIZED), "OPERATON_NOT_INITIALIZED"},
+  {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_PEER_KEY_ERROR), "PEER_KEY_ERROR"},
+  {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_SHARED_INFO_ERROR), "SHARED_INFO_ERROR"},
+  {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_UNKNOWN_DIGEST), "UNKNOWN_DIGEST"},
+  {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_UNKNOWN_MASK_DIGEST), "UNKNOWN_MASK_DIGEST"},
+  {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_UNKNOWN_PUBLIC_KEY_TYPE), "UNKNOWN_PUBLIC_KEY_TYPE"},
+  {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_UNSUPPORTED_ALGORITHM), "UNSUPPORTED_ALGORITHM"},
+  {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_UNSUPPORTED_MASK_ALGORITHM), "UNSUPPORTED_MASK_ALGORITHM"},
+  {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_UNSUPPORTED_MASK_PARAMETER), "UNSUPPORTED_MASK_PARAMETER"},
+  {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_UNSUPPORTED_PUBLIC_KEY_TYPE), "UNSUPPORTED_PUBLIC_KEY_TYPE"},
+  {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_UNSUPPORTED_SIGNATURE_TYPE), "UNSUPPORTED_SIGNATURE_TYPE"},
+  {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_X931_UNSUPPORTED), "X931_UNSUPPORTED"},
+  {0, NULL},
+};
diff --git a/crypto/evp/example_sign.c b/crypto/evp/example_sign.c
new file mode 100644
index 0000000..4bbe194
--- /dev/null
+++ b/crypto/evp/example_sign.c
@@ -0,0 +1,198 @@
+/* Copyright (c) 2014, 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 <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <openssl/bio.h>
+#include <openssl/digest.h>
+#include <openssl/evp.h>
+#include <openssl/rsa.h>
+
+
+/* kExampleRSAKeyDER is an RSA private key in ASN.1, DER format. Of course, you
+ * should never use this key anywhere but in an example. */
+static const uint8_t kExampleRSAKeyDER[] = {
+    0x30, 0x82, 0x02, 0x5c, 0x02, 0x01, 0x00, 0x02, 0x81, 0x81, 0x00, 0xf8,
+    0xb8, 0x6c, 0x83, 0xb4, 0xbc, 0xd9, 0xa8, 0x57, 0xc0, 0xa5, 0xb4, 0x59,
+    0x76, 0x8c, 0x54, 0x1d, 0x79, 0xeb, 0x22, 0x52, 0x04, 0x7e, 0xd3, 0x37,
+    0xeb, 0x41, 0xfd, 0x83, 0xf9, 0xf0, 0xa6, 0x85, 0x15, 0x34, 0x75, 0x71,
+    0x5a, 0x84, 0xa8, 0x3c, 0xd2, 0xef, 0x5a, 0x4e, 0xd3, 0xde, 0x97, 0x8a,
+    0xdd, 0xff, 0xbb, 0xcf, 0x0a, 0xaa, 0x86, 0x92, 0xbe, 0xb8, 0x50, 0xe4,
+    0xcd, 0x6f, 0x80, 0x33, 0x30, 0x76, 0x13, 0x8f, 0xca, 0x7b, 0xdc, 0xec,
+    0x5a, 0xca, 0x63, 0xc7, 0x03, 0x25, 0xef, 0xa8, 0x8a, 0x83, 0x58, 0x76,
+    0x20, 0xfa, 0x16, 0x77, 0xd7, 0x79, 0x92, 0x63, 0x01, 0x48, 0x1a, 0xd8,
+    0x7b, 0x67, 0xf1, 0x52, 0x55, 0x49, 0x4e, 0xd6, 0x6e, 0x4a, 0x5c, 0xd7,
+    0x7a, 0x37, 0x36, 0x0c, 0xde, 0xdd, 0x8f, 0x44, 0xe8, 0xc2, 0xa7, 0x2c,
+    0x2b, 0xb5, 0xaf, 0x64, 0x4b, 0x61, 0x07, 0x02, 0x03, 0x01, 0x00, 0x01,
+    0x02, 0x81, 0x80, 0x74, 0x88, 0x64, 0x3f, 0x69, 0x45, 0x3a, 0x6d, 0xc7,
+    0x7f, 0xb9, 0xa3, 0xc0, 0x6e, 0xec, 0xdc, 0xd4, 0x5a, 0xb5, 0x32, 0x85,
+    0x5f, 0x19, 0xd4, 0xf8, 0xd4, 0x3f, 0x3c, 0xfa, 0xc2, 0xf6, 0x5f, 0xee,
+    0xe6, 0xba, 0x87, 0x74, 0x2e, 0xc7, 0x0c, 0xd4, 0x42, 0xb8, 0x66, 0x85,
+    0x9c, 0x7b, 0x24, 0x61, 0xaa, 0x16, 0x11, 0xf6, 0xb5, 0xb6, 0xa4, 0x0a,
+    0xc9, 0x55, 0x2e, 0x81, 0xa5, 0x47, 0x61, 0xcb, 0x25, 0x8f, 0xc2, 0x15,
+    0x7b, 0x0e, 0x7c, 0x36, 0x9f, 0x3a, 0xda, 0x58, 0x86, 0x1c, 0x5b, 0x83,
+    0x79, 0xe6, 0x2b, 0xcc, 0xe6, 0xfa, 0x2c, 0x61, 0xf2, 0x78, 0x80, 0x1b,
+    0xe2, 0xf3, 0x9d, 0x39, 0x2b, 0x65, 0x57, 0x91, 0x3d, 0x71, 0x99, 0x73,
+    0xa5, 0xc2, 0x79, 0x20, 0x8c, 0x07, 0x4f, 0xe5, 0xb4, 0x60, 0x1f, 0x99,
+    0xa2, 0xb1, 0x4f, 0x0c, 0xef, 0xbc, 0x59, 0x53, 0x00, 0x7d, 0xb1, 0x02,
+    0x41, 0x00, 0xfc, 0x7e, 0x23, 0x65, 0x70, 0xf8, 0xce, 0xd3, 0x40, 0x41,
+    0x80, 0x6a, 0x1d, 0x01, 0xd6, 0x01, 0xff, 0xb6, 0x1b, 0x3d, 0x3d, 0x59,
+    0x09, 0x33, 0x79, 0xc0, 0x4f, 0xde, 0x96, 0x27, 0x4b, 0x18, 0xc6, 0xd9,
+    0x78, 0xf1, 0xf4, 0x35, 0x46, 0xe9, 0x7c, 0x42, 0x7a, 0x5d, 0x9f, 0xef,
+    0x54, 0xb8, 0xf7, 0x9f, 0xc4, 0x33, 0x6c, 0xf3, 0x8c, 0x32, 0x46, 0x87,
+    0x67, 0x30, 0x7b, 0xa7, 0xac, 0xe3, 0x02, 0x41, 0x00, 0xfc, 0x2c, 0xdf,
+    0x0c, 0x0d, 0x88, 0xf5, 0xb1, 0x92, 0xa8, 0x93, 0x47, 0x63, 0x55, 0xf5,
+    0xca, 0x58, 0x43, 0xba, 0x1c, 0xe5, 0x9e, 0xb6, 0x95, 0x05, 0xcd, 0xb5,
+    0x82, 0xdf, 0xeb, 0x04, 0x53, 0x9d, 0xbd, 0xc2, 0x38, 0x16, 0xb3, 0x62,
+    0xdd, 0xa1, 0x46, 0xdb, 0x6d, 0x97, 0x93, 0x9f, 0x8a, 0xc3, 0x9b, 0x64,
+    0x7e, 0x42, 0xe3, 0x32, 0x57, 0x19, 0x1b, 0xd5, 0x6e, 0x85, 0xfa, 0xb8,
+    0x8d, 0x02, 0x41, 0x00, 0xbc, 0x3d, 0xde, 0x6d, 0xd6, 0x97, 0xe8, 0xba,
+    0x9e, 0x81, 0x37, 0x17, 0xe5, 0xa0, 0x64, 0xc9, 0x00, 0xb7, 0xe7, 0xfe,
+    0xf4, 0x29, 0xd9, 0x2e, 0x43, 0x6b, 0x19, 0x20, 0xbd, 0x99, 0x75, 0xe7,
+    0x76, 0xf8, 0xd3, 0xae, 0xaf, 0x7e, 0xb8, 0xeb, 0x81, 0xf4, 0x9d, 0xfe,
+    0x07, 0x2b, 0x0b, 0x63, 0x0b, 0x5a, 0x55, 0x90, 0x71, 0x7d, 0xf1, 0xdb,
+    0xd9, 0xb1, 0x41, 0x41, 0x68, 0x2f, 0x4e, 0x39, 0x02, 0x40, 0x5a, 0x34,
+    0x66, 0xd8, 0xf5, 0xe2, 0x7f, 0x18, 0xb5, 0x00, 0x6e, 0x26, 0x84, 0x27,
+    0x14, 0x93, 0xfb, 0xfc, 0xc6, 0x0f, 0x5e, 0x27, 0xe6, 0xe1, 0xe9, 0xc0,
+    0x8a, 0xe4, 0x34, 0xda, 0xe9, 0xa2, 0x4b, 0x73, 0xbc, 0x8c, 0xb9, 0xba,
+    0x13, 0x6c, 0x7a, 0x2b, 0x51, 0x84, 0xa3, 0x4a, 0xe0, 0x30, 0x10, 0x06,
+    0x7e, 0xed, 0x17, 0x5a, 0x14, 0x00, 0xc9, 0xef, 0x85, 0xea, 0x52, 0x2c,
+    0xbc, 0x65, 0x02, 0x40, 0x51, 0xe3, 0xf2, 0x83, 0x19, 0x9b, 0xc4, 0x1e,
+    0x2f, 0x50, 0x3d, 0xdf, 0x5a, 0xa2, 0x18, 0xca, 0x5f, 0x2e, 0x49, 0xaf,
+    0x6f, 0xcc, 0xfa, 0x65, 0x77, 0x94, 0xb5, 0xa1, 0x0a, 0xa9, 0xd1, 0x8a,
+    0x39, 0x37, 0xf4, 0x0b, 0xa0, 0xd7, 0x82, 0x27, 0x5e, 0xae, 0x17, 0x17,
+    0xa1, 0x1e, 0x54, 0x34, 0xbf, 0x6e, 0xc4, 0x8e, 0x99, 0x5d, 0x08, 0xf1,
+    0x2d, 0x86, 0x9d, 0xa5, 0x20, 0x1b, 0xe5, 0xdf,
+};
+
+static const uint8_t kMsg[] = {1, 2, 3, 4};
+
+static const uint8_t kSignature[] = {
+    0xa5, 0xf0, 0x8a, 0x47, 0x5d, 0x3c, 0xb3, 0xcc, 0xa9, 0x79, 0xaf, 0x4d,
+    0x8c, 0xae, 0x4c, 0x14, 0xef, 0xc2, 0x0b, 0x34, 0x36, 0xde, 0xf4, 0x3e,
+    0x3d, 0xbb, 0x4a, 0x60, 0x5c, 0xc8, 0x91, 0x28, 0xda, 0xfb, 0x7e, 0x04,
+    0x96, 0x7e, 0x63, 0x13, 0x90, 0xce, 0xb9, 0xb4, 0x62, 0x7a, 0xfd, 0x09,
+    0x3d, 0xc7, 0x67, 0x78, 0x54, 0x04, 0xeb, 0x52, 0x62, 0x6e, 0x24, 0x67,
+    0xb4, 0x40, 0xfc, 0x57, 0x62, 0xc6, 0xf1, 0x67, 0xc1, 0x97, 0x8f, 0x6a,
+    0xa8, 0xae, 0x44, 0x46, 0x5e, 0xab, 0x67, 0x17, 0x53, 0x19, 0x3a, 0xda,
+    0x5a, 0xc8, 0x16, 0x3e, 0x86, 0xd5, 0xc5, 0x71, 0x2f, 0xfc, 0x23, 0x48,
+    0xd9, 0x0b, 0x13, 0xdd, 0x7b, 0x5a, 0x25, 0x79, 0xef, 0xa5, 0x7b, 0x04,
+    0xed, 0x44, 0xf6, 0x18, 0x55, 0xe4, 0x0a, 0xe9, 0x57, 0x79, 0x5d, 0xd7,
+    0x55, 0xa7, 0xab, 0x45, 0x02, 0x97, 0x60, 0x42,
+};
+
+
+int example_EVP_DigestSignInit() {
+  int ret = 0;
+  EVP_PKEY *pkey = NULL;
+  RSA *rsa = NULL;
+  const uint8_t *derp = kExampleRSAKeyDER;
+  uint8_t *sig = NULL;
+  size_t sig_len;
+  EVP_MD_CTX md_ctx;
+
+  EVP_MD_CTX_init(&md_ctx);
+
+  if (!d2i_RSAPrivateKey(&rsa, &derp, sizeof(kExampleRSAKeyDER))) {
+    goto out;
+  }
+
+  sig_len = RSA_size(rsa);
+
+  pkey = EVP_PKEY_new();
+  sig = malloc(sig_len);
+  if (pkey == NULL ||
+      sig == NULL ||
+      !EVP_PKEY_set1_RSA(pkey, rsa) ||
+      EVP_DigestSignInit(&md_ctx, NULL, EVP_sha256(), NULL, pkey) != 1 ||
+      EVP_DigestSignUpdate(&md_ctx, kMsg, sizeof(kMsg)) != 1 ||
+      EVP_DigestSignFinal(&md_ctx, sig, &sig_len) != 1) {
+    goto out;
+  }
+  ret = 1;
+
+out:
+  if (!ret) {
+    BIO_print_errors_fp(stderr);
+  }
+
+  EVP_MD_CTX_cleanup(&md_ctx);
+  if (pkey) {
+    EVP_PKEY_free(pkey);
+  }
+  if (rsa) {
+    RSA_free(rsa);
+  }
+  if (sig) {
+    free(sig);
+  }
+
+  return ret;
+}
+
+int example_EVP_DigestVerifyInit() {
+  int ret = 0;
+  EVP_PKEY *pkey = NULL;
+  RSA *rsa = NULL;
+  const uint8_t *derp = kExampleRSAKeyDER;
+  EVP_MD_CTX md_ctx;
+
+  EVP_MD_CTX_init(&md_ctx);
+
+  if (!d2i_RSAPrivateKey(&rsa, &derp, sizeof(kExampleRSAKeyDER))) {
+    goto out;
+  }
+
+  pkey = EVP_PKEY_new();
+  if (pkey == NULL ||
+      !EVP_PKEY_set1_RSA(pkey, rsa) ||
+      EVP_DigestVerifyInit(&md_ctx, NULL, EVP_sha256(), NULL, pkey) != 1 ||
+      EVP_DigestVerifyUpdate(&md_ctx, kMsg, sizeof(kMsg)) != 1 ||
+      EVP_DigestVerifyFinal(&md_ctx, kSignature, sizeof(kSignature)) != 1) {
+    goto out;
+  }
+  ret = 1;
+
+out:
+  if (!ret) {
+    BIO_print_errors_fp(stderr);
+  }
+
+  EVP_MD_CTX_cleanup(&md_ctx);
+  if (pkey) {
+    EVP_PKEY_free(pkey);
+  }
+  if (rsa) {
+    RSA_free(rsa);
+  }
+
+  return ret;
+}
+
+int main() {
+  if (!example_EVP_DigestSignInit()) {
+    fprintf(stderr, "EVP_DigestSignInit failed\n");
+    return 1;
+  }
+
+  if (!example_EVP_DigestVerifyInit()) {
+    fprintf(stderr, "EVP_DigestVerifyInit failed\n");
+    return 1;
+  }
+
+  printf("PASS\n");
+  return 0;
+}
diff --git a/crypto/evp/internal.h b/crypto/evp/internal.h
new file mode 100644
index 0000000..76f206e
--- /dev/null
+++ b/crypto/evp/internal.h
@@ -0,0 +1,233 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.] */
+
+#ifndef OPENSSL_HEADER_EVP_INTERNAL_H
+#define OPENSSL_HEADER_EVP_INTERNAL_H
+
+#include <openssl/base.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+/* These values are flags for EVP_PKEY_ASN1_METHOD.flags. */
+#define ASN1_PKEY_ALIAS 0x1
+#define ASN1_PKEY_DYNAMIC 0x2
+#define ASN1_PKEY_SIGPARAM_NULL 0x4
+
+struct evp_pkey_asn1_method_st {
+  int pkey_id;
+  int pkey_base_id;
+  unsigned long pkey_flags;
+
+  char *pem_str;
+  char *info;
+
+  int (*pub_decode)(EVP_PKEY *pk, X509_PUBKEY *pub);
+  int (*pub_encode)(X509_PUBKEY *pub, const EVP_PKEY *pk);
+  int (*pub_cmp)(const EVP_PKEY *a, const EVP_PKEY *b);
+  int (*pub_print)(BIO *out, const EVP_PKEY *pkey, int indent, ASN1_PCTX *pctx);
+
+  int (*priv_decode)(EVP_PKEY *pk, PKCS8_PRIV_KEY_INFO *p8inf);
+  int (*priv_encode)(PKCS8_PRIV_KEY_INFO *p8, const EVP_PKEY *pk);
+  int (*priv_print)(BIO *out, const EVP_PKEY *pkey, int indent,
+                    ASN1_PCTX *pctx);
+
+  int (*pkey_size)(const EVP_PKEY *pk);
+  int (*pkey_bits)(const EVP_PKEY *pk);
+
+  int (*param_decode)(EVP_PKEY *pkey, const unsigned char **pder, int derlen);
+  int (*param_encode)(const EVP_PKEY *pkey, unsigned char **pder);
+  int (*param_missing)(const EVP_PKEY *pk);
+  int (*param_copy)(EVP_PKEY *to, const EVP_PKEY *from);
+  int (*param_cmp)(const EVP_PKEY *a, const EVP_PKEY *b);
+  int (*param_print)(BIO *out, const EVP_PKEY *pkey, int indent,
+                     ASN1_PCTX *pctx);
+  int (*sig_print)(BIO *out, const X509_ALGOR *sigalg, const ASN1_STRING *sig,
+                   int indent, ASN1_PCTX *pctx);
+
+
+  void (*pkey_free)(EVP_PKEY *pkey);
+  int (*pkey_ctrl)(EVP_PKEY *pkey, int op, long arg1, void *arg2);
+
+  /* Legacy functions for old PEM */
+
+  int (*old_priv_decode)(EVP_PKEY *pkey, const unsigned char **pder,
+                         int derlen);
+  int (*old_priv_encode)(const EVP_PKEY *pkey, unsigned char **pder);
+  /* Custom ASN1 signature verification */
+  int (*item_verify)(EVP_MD_CTX *ctx, const ASN1_ITEM *it, void *asn,
+                     X509_ALGOR *a, ASN1_BIT_STRING *sig, EVP_PKEY *pkey);
+  int (*item_sign)(EVP_MD_CTX *ctx, const ASN1_ITEM *it, void *asn,
+                   X509_ALGOR *alg1, X509_ALGOR *alg2, ASN1_BIT_STRING *sig);
+
+} /* EVP_PKEY_ASN1_METHOD */;
+
+
+typedef int EVP_PKEY_gen_cb(EVP_PKEY_CTX *ctx);
+
+#define EVP_PKEY_OP_UNDEFINED 0
+#define EVP_PKEY_OP_PARAMGEN (1 << 1)
+#define EVP_PKEY_OP_KEYGEN (1 << 2)
+#define EVP_PKEY_OP_SIGN (1 << 3)
+#define EVP_PKEY_OP_VERIFY (1 << 4)
+#define EVP_PKEY_OP_VERIFYRECOVER (1 << 5)
+#define EVP_PKEY_OP_SIGNCTX (1 << 6)
+#define EVP_PKEY_OP_VERIFYCTX (1 << 7)
+#define EVP_PKEY_OP_ENCRYPT (1 << 8)
+#define EVP_PKEY_OP_DECRYPT (1 << 9)
+#define EVP_PKEY_OP_DERIVE (1 << 10)
+
+#define EVP_PKEY_OP_TYPE_SIG                                           \
+  (EVP_PKEY_OP_SIGN | EVP_PKEY_OP_VERIFY | EVP_PKEY_OP_VERIFYRECOVER | \
+   EVP_PKEY_OP_SIGNCTX | EVP_PKEY_OP_VERIFYCTX)
+
+#define EVP_PKEY_OP_TYPE_CRYPT (EVP_PKEY_OP_ENCRYPT | EVP_PKEY_OP_DECRYPT)
+
+#define EVP_PKEY_OP_TYPE_NOGEN \
+  (EVP_PKEY_OP_SIG | EVP_PKEY_OP_CRYPT | EVP_PKEY_OP_DERIVE)
+
+#define EVP_PKEY_OP_TYPE_GEN (EVP_PKEY_OP_PARAMGEN | EVP_PKEY_OP_KEYGEN)
+
+#define EVP_PKEY_CTRL_MD 1
+#define EVP_PKEY_CTRL_GET_MD 2
+#define EVP_PKEY_CTRL_RSA_PADDING (EVP_PKEY_ALG_CTRL + 1)
+#define EVP_PKEY_CTRL_GET_RSA_PADDING (EVP_PKEY_ALG_CTRL + 2)
+#define EVP_PKEY_CTRL_RSA_PSS_SALTLEN (EVP_PKEY_ALG_CTRL + 3)
+#define EVP_PKEY_CTRL_GET_RSA_PSS_SALTLEN (EVP_PKEY_ALG_CTRL + 4)
+#define EVP_PKEY_CTRL_RSA_KEYGEN_BITS (EVP_PKEY_ALG_CTRL + 5)
+#define EVP_PKEY_CTRL_RSA_KEYGEN_PUBEXP	(EVP_PKEY_ALG_CTRL + 6)
+#define EVP_PKEY_CTRL_RSA_OAEP_MD (EVP_PKEY_ALG_CTRL + 7)
+#define EVP_PKEY_CTRL_GET_RSA_OAEP_MD (EVP_PKEY_ALG_CTRL + 8)
+#define EVP_PKEY_CTRL_RSA_MGF1_MD (EVP_PKEY_ALG_CTRL + 9)
+#define EVP_PKEY_CTRL_GET_RSA_MGF1_MD (EVP_PKEY_ALG_CTRL + 10)
+#define EVP_PKEY_CTRL_RSA_OAEP_LABEL (EVP_PKEY_ALG_CTRL + 11)
+#define EVP_PKEY_CTRL_GET_RSA_OAEP_LABEL (EVP_PKEY_ALG_CTRL + 12)
+
+struct evp_pkey_ctx_st {
+  /* Method associated with this operation */
+  const EVP_PKEY_METHOD *pmeth;
+  /* Engine that implements this method or NULL if builtin */
+  ENGINE *engine;
+  /* Key: may be NULL */
+  EVP_PKEY *pkey;
+  /* Peer key for key agreement, may be NULL */
+  EVP_PKEY *peerkey;
+  /* operation contains one of the |EVP_PKEY_OP_*| values. */
+  int operation;
+  /* Algorithm specific data */
+  void *data;
+  /* Application specific data */
+  void *app_data;
+} /* EVP_PKEY_CTX */;
+
+/* EVP_PKEY_FLAG_AUTOARGLEN causes wrapper functions to automatically check the
+ * argument length to various functions (signing, decrypting etc) is equal to
+ * the value of |EVP_PKEY_size|. */
+#define EVP_PKEY_FLAG_AUTOARGLEN 2
+
+struct evp_pkey_method_st {
+  int pkey_id;
+  int flags;
+
+  int (*init)(EVP_PKEY_CTX *ctx);
+  int (*copy)(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src);
+  void (*cleanup)(EVP_PKEY_CTX *ctx);
+
+  int (*paramgen_init)(EVP_PKEY_CTX *ctx);
+  int (*paramgen)(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey);
+
+  int (*keygen_init)(EVP_PKEY_CTX *ctx);
+  int (*keygen)(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey);
+
+  int (*sign_init)(EVP_PKEY_CTX *ctx);
+  int (*sign)(EVP_PKEY_CTX *ctx, unsigned char *sig, size_t *siglen,
+              const unsigned char *tbs, size_t tbslen);
+
+  int (*verify_init)(EVP_PKEY_CTX *ctx);
+  int (*verify)(EVP_PKEY_CTX *ctx, const unsigned char *sig, size_t siglen,
+                const unsigned char *tbs, size_t tbslen);
+
+  int (*signctx_init)(EVP_PKEY_CTX *ctx, EVP_MD_CTX *mctx);
+  int (*signctx)(EVP_PKEY_CTX *ctx, unsigned char *sig, size_t *siglen,
+                 EVP_MD_CTX *mctx);
+
+  int (*verifyctx_init)(EVP_PKEY_CTX *ctx, EVP_MD_CTX *mctx);
+  int (*verifyctx)(EVP_PKEY_CTX *ctx, const unsigned char *sig, int siglen,
+                   EVP_MD_CTX *mctx);
+
+  int (*encrypt_init)(EVP_PKEY_CTX *ctx);
+  int (*encrypt)(EVP_PKEY_CTX *ctx, unsigned char *out, size_t *outlen,
+                 const unsigned char *in, size_t inlen);
+
+  int (*decrypt_init)(EVP_PKEY_CTX *ctx);
+  int (*decrypt)(EVP_PKEY_CTX *ctx, unsigned char *out, size_t *outlen,
+                 const unsigned char *in, size_t inlen);
+
+  int (*derive_init)(EVP_PKEY_CTX *ctx);
+  int (*derive)(EVP_PKEY_CTX *ctx, unsigned char *key, size_t *keylen);
+
+  int (*ctrl)(EVP_PKEY_CTX *ctx, int type, int p1, void *p2);
+  int (*ctrl_str)(EVP_PKEY_CTX *ctx, const char *type, const char *value);
+} /* EVP_PKEY_METHOD */;
+
+
+#if defined(__cplusplus)
+}  /* extern C */
+#endif
+
+#endif  /* OPENSSL_HEADER_EVP_INTERNAL_H */
diff --git a/crypto/evp/p_ec.c b/crypto/evp/p_ec.c
new file mode 100644
index 0000000..2305e6e
--- /dev/null
+++ b/crypto/evp/p_ec.c
@@ -0,0 +1,423 @@
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project 2006.
+ */
+/* ====================================================================
+ * Copyright (c) 2006 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    licensing@OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com). */
+
+#include <openssl/evp.h>
+
+#include <openssl/asn1.h>
+#include <openssl/bn.h>
+#include <openssl/buf.h>
+#include <openssl/digest.h>
+#include <openssl/ec.h>
+#include <openssl/ec_key.h>
+#include <openssl/ecdh.h>
+#include <openssl/ecdsa.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+#include <openssl/obj.h>
+
+#include "internal.h"
+#include "../ec/internal.h"
+
+
+typedef struct {
+  /* Key and paramgen group */
+  EC_GROUP *gen_group;
+  /* message digest */
+  const EVP_MD *md;
+  /* Duplicate key if custom cofactor needed */
+  EC_KEY *co_key;
+  /* Cofactor mode */
+  signed char cofactor_mode;
+  /* KDF (if any) to use for ECDH */
+  char kdf_type;
+  /* Message digest to use for key derivation */
+  const EVP_MD *kdf_md;
+  /* User key material */
+  unsigned char *kdf_ukm;
+  size_t kdf_ukmlen;
+  /* KDF output length */
+  size_t kdf_outlen;
+} EC_PKEY_CTX;
+
+
+static int pkey_ec_init(EVP_PKEY_CTX *ctx) {
+  EC_PKEY_CTX *dctx;
+  dctx = OPENSSL_malloc(sizeof(EC_PKEY_CTX));
+  if (!dctx) {
+    return 0;
+  }
+  memset(dctx, 0, sizeof(EC_PKEY_CTX));
+  dctx->cofactor_mode = -1;
+  dctx->kdf_type = EVP_PKEY_ECDH_KDF_NONE;
+
+  ctx->data = dctx;
+
+  return 1;
+}
+
+static int pkey_ec_copy(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src) {
+  EC_PKEY_CTX *dctx, *sctx;
+  if (!pkey_ec_init(dst)) {
+    return 0;
+  }
+  sctx = src->data;
+  dctx = dst->data;
+
+  if (sctx->gen_group) {
+    dctx->gen_group = EC_GROUP_dup(sctx->gen_group);
+    if (!dctx->gen_group) {
+      return 0;
+    }
+  }
+  dctx->md = sctx->md;
+
+  if (sctx->co_key) {
+    dctx->co_key = EC_KEY_dup(sctx->co_key);
+    if (!dctx->co_key) {
+      return 0;
+    }
+  }
+  dctx->kdf_type = sctx->kdf_type;
+  dctx->kdf_md = sctx->kdf_md;
+  dctx->kdf_outlen = sctx->kdf_outlen;
+  if (sctx->kdf_ukm) {
+    dctx->kdf_ukm = BUF_memdup(sctx->kdf_ukm, sctx->kdf_ukmlen);
+    if (!dctx->kdf_ukm) {
+      return 0;
+    }
+  } else {
+    dctx->kdf_ukm = NULL;
+  }
+  dctx->kdf_ukmlen = sctx->kdf_ukmlen;
+  return 1;
+}
+
+static void pkey_ec_cleanup(EVP_PKEY_CTX *ctx) {
+  EC_PKEY_CTX *dctx = ctx->data;
+  if (!dctx) {
+    return;
+  }
+
+  if (dctx->gen_group) {
+    EC_GROUP_free(dctx->gen_group);
+  }
+  if (dctx->co_key) {
+    EC_KEY_free(dctx->co_key);
+  }
+  if (dctx->kdf_ukm) {
+    OPENSSL_free(dctx->kdf_ukm);
+  }
+  OPENSSL_free(dctx);
+}
+
+static int pkey_ec_sign(EVP_PKEY_CTX *ctx, uint8_t *sig, size_t *siglen,
+                        const uint8_t *tbs, size_t tbslen) {
+  int ret, type;
+  unsigned int sltmp;
+  EC_PKEY_CTX *dctx = ctx->data;
+  EC_KEY *ec = ctx->pkey->pkey.ec;
+
+  if (!sig) {
+    *siglen = ECDSA_size(ec);
+    return 1;
+  } else if (*siglen < (size_t)ECDSA_size(ec)) {
+    OPENSSL_PUT_ERROR(EVP, pkey_ec_sign, EVP_R_BUFFER_TOO_SMALL);
+    return 0;
+  }
+
+  type = NID_sha1;
+  if (dctx->md) {
+    type = EVP_MD_type(dctx->md);
+  }
+
+  ret = ECDSA_sign(type, tbs, tbslen, sig, &sltmp, ec);
+
+  if (ret <= 0) {
+    return ret;
+  }
+  *siglen = (size_t)sltmp;
+  return 1;
+}
+
+static int pkey_ec_verify(EVP_PKEY_CTX *ctx, const uint8_t *sig, size_t siglen,
+                          const uint8_t *tbs, size_t tbslen) {
+  int type;
+  EC_PKEY_CTX *dctx = ctx->data;
+  EC_KEY *ec = ctx->pkey->pkey.ec;
+
+  type = NID_sha1;
+  if (dctx->md) {
+    type = EVP_MD_type(dctx->md);
+  }
+
+  return ECDSA_verify(type, tbs, tbslen, sig, siglen, ec);
+}
+
+static int pkey_ec_derive(EVP_PKEY_CTX *ctx, uint8_t *key,
+                          size_t *keylen) {
+  int ret;
+  size_t outlen;
+  const EC_POINT *pubkey = NULL;
+  EC_KEY *eckey;
+  EC_PKEY_CTX *dctx = ctx->data;
+
+  if (!ctx->pkey || !ctx->peerkey) {
+    OPENSSL_PUT_ERROR(EVP, pkey_ec_derive, EVP_R_KEYS_NOT_SET);
+    return 0;
+  }
+
+  eckey = dctx->co_key ? dctx->co_key : ctx->pkey->pkey.ec;
+
+  if (!key) {
+    const EC_GROUP *group;
+    group = EC_KEY_get0_group(eckey);
+    *keylen = (EC_GROUP_get_degree(group) + 7) / 8;
+    return 1;
+  }
+  pubkey = EC_KEY_get0_public_key(ctx->peerkey->pkey.ec);
+
+  /* NB: unlike PKCS#3 DH, if *outlen is less than maximum size this is
+   * not an error, the result is truncated. */
+
+  outlen = *keylen;
+
+  ret = ECDH_compute_key(key, outlen, pubkey, eckey, 0);
+  if (ret < 0) {
+    return ret;
+  }
+  *keylen = ret;
+  return 1;
+}
+
+static int pkey_ec_kdf_derive(EVP_PKEY_CTX *ctx, uint8_t *key,
+                              size_t *keylen) {
+  EC_PKEY_CTX *dctx = ctx->data;
+  uint8_t *ktmp = NULL;
+  size_t ktmplen;
+  int rv = 0;
+
+  if (dctx->kdf_type == EVP_PKEY_ECDH_KDF_NONE) {
+    return pkey_ec_derive(ctx, key, keylen);
+  }
+  if (!key) {
+    *keylen = dctx->kdf_outlen;
+    return 1;
+  }
+  if (*keylen != dctx->kdf_outlen ||
+      !pkey_ec_derive(ctx, NULL, &ktmplen)) {
+    return 0;
+  }
+  ktmp = OPENSSL_malloc(ktmplen);
+  if (!ktmp) {
+    return 0;
+  }
+  if (!pkey_ec_derive(ctx, ktmp, &ktmplen)) {
+    goto err;
+  }
+
+  if (!ECDH_KDF_X9_62(key, *keylen, ktmp, ktmplen, dctx->kdf_ukm,
+                      dctx->kdf_ukmlen, dctx->kdf_md)) {
+    goto err;
+  }
+  rv = 1;
+
+err:
+  if (ktmp) {
+    OPENSSL_cleanse(ktmp, ktmplen);
+    OPENSSL_free(ktmp);
+  }
+  return rv;
+}
+
+static int pkey_ec_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2) {
+  EC_PKEY_CTX *dctx = ctx->data;
+  EC_GROUP *group;
+
+  switch (type) {
+    case EVP_PKEY_CTRL_EC_PARAMGEN_CURVE_NID:
+      group = EC_GROUP_new_by_curve_name(p1);
+      if (group == NULL) {
+        OPENSSL_PUT_ERROR(EVP, pkey_ec_ctrl, EVP_R_INVALID_CURVE);
+        return 0;
+      }
+      if (dctx->gen_group)
+        EC_GROUP_free(dctx->gen_group);
+      dctx->gen_group = group;
+      return 1;
+
+    case EVP_PKEY_CTRL_EC_KDF_TYPE:
+      if (p1 == -2)
+        return dctx->kdf_type;
+      if (p1 != EVP_PKEY_ECDH_KDF_NONE && p1 != EVP_PKEY_ECDH_KDF_X9_62)
+        return -2;
+      dctx->kdf_type = p1;
+      return 1;
+
+    case EVP_PKEY_CTRL_EC_KDF_MD:
+      dctx->kdf_md = p2;
+      return 1;
+
+    case EVP_PKEY_CTRL_GET_EC_KDF_MD:
+      *(const EVP_MD **)p2 = dctx->kdf_md;
+      return 1;
+
+    case EVP_PKEY_CTRL_EC_KDF_OUTLEN:
+      if (p1 <= 0)
+        return -2;
+      dctx->kdf_outlen = (size_t)p1;
+      return 1;
+
+    case EVP_PKEY_CTRL_GET_EC_KDF_OUTLEN:
+      *(int *)p2 = dctx->kdf_outlen;
+      return 1;
+
+    case EVP_PKEY_CTRL_EC_KDF_UKM:
+      if (dctx->kdf_ukm)
+        OPENSSL_free(dctx->kdf_ukm);
+      dctx->kdf_ukm = p2;
+      if (p2)
+        dctx->kdf_ukmlen = p1;
+      else
+        dctx->kdf_ukmlen = 0;
+      return 1;
+
+    case EVP_PKEY_CTRL_GET_EC_KDF_UKM:
+      *(unsigned char **)p2 = dctx->kdf_ukm;
+      return dctx->kdf_ukmlen;
+
+    case EVP_PKEY_CTRL_MD:
+      if (EVP_MD_type((const EVP_MD *)p2) != NID_sha1 &&
+          EVP_MD_type((const EVP_MD *)p2) != NID_ecdsa_with_SHA1 &&
+          EVP_MD_type((const EVP_MD *)p2) != NID_sha224 &&
+          EVP_MD_type((const EVP_MD *)p2) != NID_sha256 &&
+          EVP_MD_type((const EVP_MD *)p2) != NID_sha384 &&
+          EVP_MD_type((const EVP_MD *)p2) != NID_sha512) {
+        OPENSSL_PUT_ERROR(EVP, pkey_ec_ctrl, EVP_R_INVALID_DIGEST_TYPE);
+        return 0;
+      }
+      dctx->md = p2;
+      return 1;
+
+    case EVP_PKEY_CTRL_GET_MD:
+      *(const EVP_MD **)p2 = dctx->md;
+      return 1;
+
+    case EVP_PKEY_CTRL_PEER_KEY:
+    /* Default behaviour is OK */
+    case EVP_PKEY_CTRL_DIGESTINIT:
+      return 1;
+
+    default:
+      return -2;
+  }
+}
+
+static int pkey_ec_paramgen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) {
+  EC_KEY *ec = NULL;
+  EC_PKEY_CTX *dctx = ctx->data;
+  int ret = 0;
+
+  if (dctx->gen_group == NULL) {
+    OPENSSL_PUT_ERROR(EVP, pkey_ec_paramgen, EVP_R_NO_PARAMETERS_SET);
+    return 0;
+  }
+  ec = EC_KEY_new();
+  if (!ec) {
+    return 0;
+  }
+  ret = EC_KEY_set_group(ec, dctx->gen_group);
+  if (ret) {
+    EVP_PKEY_assign_EC_KEY(pkey, ec);
+  } else {
+    EC_KEY_free(ec);
+  }
+  return ret;
+}
+
+static int pkey_ec_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) {
+  EC_KEY *ec = NULL;
+  EC_PKEY_CTX *dctx = ctx->data;
+  if (ctx->pkey == NULL && dctx->gen_group == NULL) {
+    OPENSSL_PUT_ERROR(EVP, pkey_ec_keygen, EVP_R_NO_PARAMETERS_SET);
+    return 0;
+  }
+  ec = EC_KEY_new();
+  if (!ec) {
+    return 0;
+  }
+  EVP_PKEY_assign_EC_KEY(pkey, ec);
+  if (ctx->pkey) {
+    /* Note: if error return, pkey is freed by parent routine */
+    if (!EVP_PKEY_copy_parameters(pkey, ctx->pkey)) {
+      return 0;
+    }
+  } else {
+    if (!EC_KEY_set_group(ec, dctx->gen_group)) {
+      return 0;
+    }
+  }
+  return EC_KEY_generate_key(pkey->pkey.ec);
+}
+
+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 /* signctx_init */, 0 /* signctx */,
+    0 /* verifyctx_init */, 0 /* verifyctx */,    0 /* encrypt_init */,
+    0 /* encrypt */,        0 /* decrypt_init */, 0 /* decrypt */,
+    0 /* derive_init */,    pkey_ec_kdf_derive,   pkey_ec_ctrl,
+};
diff --git a/crypto/evp/p_ec_asn1.c b/crypto/evp/p_ec_asn1.c
new file mode 100644
index 0000000..d4eec13
--- /dev/null
+++ b/crypto/evp/p_ec_asn1.c
@@ -0,0 +1,577 @@
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project 2006.
+ */
+/* ====================================================================
+ * Copyright (c) 2006 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    licensing@OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com). */
+
+#include <openssl/evp.h>
+
+#include <openssl/asn1t.h>
+#include <openssl/bn.h>
+#include <openssl/ec.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+#include <openssl/obj.h>
+#include <openssl/x509.h>
+
+#include "internal.h"
+
+
+static int eckey_param2type(int *pptype, void **ppval, EC_KEY *ec_key) {
+  const EC_GROUP *group;
+  int nid;
+
+  if (ec_key == NULL || (group = EC_KEY_get0_group(ec_key)) == NULL) {
+    OPENSSL_PUT_ERROR(EVP, eckey_param2type, EVP_R_MISSING_PARAMETERS);
+    return 0;
+  }
+
+  nid = EC_GROUP_get_curve_name(group);
+  if (nid == NID_undef) {
+    OPENSSL_PUT_ERROR(EVP, eckey_param2type, EVP_R_NO_NID_FOR_CURVE);
+    return 0;
+  }
+
+  *ppval = (void*) OBJ_nid2obj(nid);
+  *pptype = V_ASN1_OBJECT;
+  return 1;
+}
+
+static int eckey_pub_encode(X509_PUBKEY *pk, const EVP_PKEY *pkey) {
+  EC_KEY *ec_key = pkey->pkey.ec;
+  void *pval = NULL;
+  int ptype;
+  uint8_t *penc = NULL, *p;
+  int penclen;
+
+  if (!eckey_param2type(&ptype, &pval, ec_key)) {
+    OPENSSL_PUT_ERROR(EVP, eckey_pub_encode, ERR_R_EC_LIB);
+    return 0;
+  }
+  penclen = i2o_ECPublicKey(ec_key, NULL);
+  if (penclen <= 0) {
+    goto err;
+  }
+  penc = OPENSSL_malloc(penclen);
+  if (!penc) {
+    goto err;
+  }
+  p = penc;
+  penclen = i2o_ECPublicKey(ec_key, &p);
+  if (penclen <= 0) {
+    goto err;
+  }
+  if (X509_PUBKEY_set0_param(pk, OBJ_nid2obj(EVP_PKEY_EC), ptype, pval, penc,
+                             penclen)) {
+    return 1;
+  }
+
+err:
+  if (ptype == V_ASN1_OBJECT) {
+    ASN1_OBJECT_free(pval);
+  } else {
+    ASN1_STRING_free(pval);
+  }
+  if (penc) {
+    OPENSSL_free(penc);
+  }
+  return 0;
+}
+
+static EC_KEY *eckey_type2param(int ptype, void *pval) {
+  EC_KEY *eckey = NULL;
+
+  if (ptype == V_ASN1_SEQUENCE) {
+    ASN1_STRING *pstr = pval;
+    const uint8_t *pm = pstr->data;
+    int pmlen = pstr->length;
+
+    eckey = d2i_ECParameters(NULL, &pm, pmlen);
+    if (eckey == NULL) {
+      OPENSSL_PUT_ERROR(EVP, eckey_type2param, EVP_R_DECODE_ERROR);
+      goto err;
+    }
+  } else if (ptype == V_ASN1_OBJECT) {
+    ASN1_OBJECT *poid = pval;
+    EC_GROUP *group;
+
+    /* type == V_ASN1_OBJECT => the parameters are given
+     * by an asn1 OID */
+    eckey = EC_KEY_new();
+    if (eckey == NULL) {
+      OPENSSL_PUT_ERROR(EVP, eckey_type2param, ERR_R_MALLOC_FAILURE);
+      goto err;
+    }
+    group = EC_GROUP_new_by_curve_name(OBJ_obj2nid(poid));
+    if (group == NULL) {
+      goto err;
+    }
+    if (EC_KEY_set_group(eckey, group) == 0) {
+      goto err;
+    }
+    EC_GROUP_free(group);
+  } else {
+    OPENSSL_PUT_ERROR(EVP, eckey_type2param, EVP_R_DECODE_ERROR);
+    goto err;
+  }
+
+  return eckey;
+
+err:
+  if (eckey) {
+    EC_KEY_free(eckey);
+  }
+  return NULL;
+}
+
+static int eckey_pub_decode(EVP_PKEY *pkey, X509_PUBKEY *pubkey) {
+  const uint8_t *p = NULL;
+  void *pval;
+  int ptype, pklen;
+  EC_KEY *eckey = NULL;
+  X509_ALGOR *palg;
+
+  if (!X509_PUBKEY_get0_param(NULL, &p, &pklen, &palg, pubkey)) {
+    return 0;
+  }
+  X509_ALGOR_get0(NULL, &ptype, &pval, palg);
+
+  eckey = eckey_type2param(ptype, pval);
+  if (!eckey) {
+    OPENSSL_PUT_ERROR(EVP, eckey_pub_decode, ERR_R_EC_LIB);
+    return 0;
+  }
+
+  /* We have parameters now set public key */
+  if (!o2i_ECPublicKey(&eckey, &p, pklen)) {
+    OPENSSL_PUT_ERROR(EVP, eckey_pub_decode, EVP_R_DECODE_ERROR);
+    goto err;
+  }
+
+  EVP_PKEY_assign_EC_KEY(pkey, eckey);
+  return 1;
+
+err:
+  if (eckey)
+    EC_KEY_free(eckey);
+  return 0;
+}
+
+static int eckey_pub_cmp(const EVP_PKEY *a, const EVP_PKEY *b) {
+  int r;
+  const EC_GROUP *group = EC_KEY_get0_group(b->pkey.ec);
+  const EC_POINT *pa = EC_KEY_get0_public_key(a->pkey.ec),
+                 *pb = EC_KEY_get0_public_key(b->pkey.ec);
+  r = EC_POINT_cmp(group, pa, pb, NULL);
+  if (r == 0) {
+    return 1;
+  } else if (r == 1) {
+    return 0;
+  } else {
+    return -2;
+  }
+}
+
+static int eckey_priv_decode(EVP_PKEY *pkey, PKCS8_PRIV_KEY_INFO *p8) {
+  const uint8_t *p = NULL;
+  void *pval;
+  int ptype, pklen;
+  EC_KEY *eckey = NULL;
+  X509_ALGOR *palg;
+
+  if (!PKCS8_pkey_get0(NULL, &p, &pklen, &palg, p8)) {
+    return 0;
+  }
+  X509_ALGOR_get0(NULL, &ptype, &pval, palg);
+
+  eckey = eckey_type2param(ptype, pval);
+
+  if (!eckey)
+    goto ecliberr;
+
+  /* We have parameters now set private key */
+  if (!d2i_ECPrivateKey(&eckey, &p, pklen)) {
+    OPENSSL_PUT_ERROR(EVP, eckey_priv_decode, EVP_R_DECODE_ERROR);
+    goto ecerr;
+  }
+
+  /* calculate public key (if necessary) */
+  if (EC_KEY_get0_public_key(eckey) == NULL) {
+    const BIGNUM *priv_key;
+    const EC_GROUP *group;
+    EC_POINT *pub_key;
+    /* the public key was not included in the SEC1 private
+     * key => calculate the public key */
+    group = EC_KEY_get0_group(eckey);
+    pub_key = EC_POINT_new(group);
+    if (pub_key == NULL) {
+      OPENSSL_PUT_ERROR(EVP, eckey_priv_decode, ERR_R_EC_LIB);
+      goto ecliberr;
+    }
+    if (!EC_POINT_copy(pub_key, EC_GROUP_get0_generator(group))) {
+      EC_POINT_free(pub_key);
+      OPENSSL_PUT_ERROR(EVP, eckey_priv_decode, ERR_R_EC_LIB);
+      goto ecliberr;
+    }
+    priv_key = EC_KEY_get0_private_key(eckey);
+    if (!EC_POINT_mul(group, pub_key, priv_key, NULL, NULL, NULL)) {
+      EC_POINT_free(pub_key);
+      OPENSSL_PUT_ERROR(EVP, eckey_priv_decode, ERR_R_EC_LIB);
+      goto ecliberr;
+    }
+    if (EC_KEY_set_public_key(eckey, pub_key) == 0) {
+      EC_POINT_free(pub_key);
+      OPENSSL_PUT_ERROR(EVP, eckey_priv_decode, ERR_R_EC_LIB);
+      goto ecliberr;
+    }
+    EC_POINT_free(pub_key);
+  }
+
+  EVP_PKEY_assign_EC_KEY(pkey, eckey);
+  return 1;
+
+ecliberr:
+  OPENSSL_PUT_ERROR(EVP, eckey_priv_decode, ERR_R_EC_LIB);
+ecerr:
+  if (eckey)
+    EC_KEY_free(eckey);
+  return 0;
+}
+
+static int eckey_priv_encode(PKCS8_PRIV_KEY_INFO *p8, const EVP_PKEY *pkey) {
+  EC_KEY *ec_key;
+  uint8_t *ep, *p;
+  int eplen, ptype;
+  void *pval;
+  unsigned int tmp_flags, old_flags;
+
+  ec_key = pkey->pkey.ec;
+
+  if (!eckey_param2type(&ptype, &pval, ec_key)) {
+    OPENSSL_PUT_ERROR(EVP, eckey_priv_encode, EVP_R_DECODE_ERROR);
+    return 0;
+  }
+
+  /* set the private key */
+
+  /* do not include the parameters in the SEC1 private key
+   * see PKCS#11 12.11 */
+  old_flags = EC_KEY_get_enc_flags(ec_key);
+  tmp_flags = old_flags | EC_PKEY_NO_PARAMETERS;
+  EC_KEY_set_enc_flags(ec_key, tmp_flags);
+  eplen = i2d_ECPrivateKey(ec_key, NULL);
+  if (!eplen) {
+    EC_KEY_set_enc_flags(ec_key, old_flags);
+    OPENSSL_PUT_ERROR(EVP, eckey_priv_encode, ERR_R_EC_LIB);
+    return 0;
+  }
+  ep = (uint8_t *)OPENSSL_malloc(eplen);
+  if (!ep) {
+    EC_KEY_set_enc_flags(ec_key, old_flags);
+    OPENSSL_PUT_ERROR(EVP, eckey_priv_encode, ERR_R_MALLOC_FAILURE);
+    return 0;
+  }
+  p = ep;
+  if (!i2d_ECPrivateKey(ec_key, &p)) {
+    EC_KEY_set_enc_flags(ec_key, old_flags);
+    OPENSSL_free(ep);
+    OPENSSL_PUT_ERROR(EVP, eckey_priv_encode, ERR_R_EC_LIB);
+    return 0;
+  }
+  /* restore old encoding flags */
+  EC_KEY_set_enc_flags(ec_key, old_flags);
+
+  if (!PKCS8_pkey_set0(p8, (ASN1_OBJECT *)OBJ_nid2obj(NID_X9_62_id_ecPublicKey),
+                       0, ptype, pval, ep, eplen)) {
+    return 0;
+  }
+
+  return 1;
+}
+
+static int int_ec_size(const EVP_PKEY *pkey) {
+  return ECDSA_size(pkey->pkey.ec);
+}
+
+static int ec_bits(const EVP_PKEY *pkey) {
+  BIGNUM *order = BN_new();
+  const EC_GROUP *group;
+  int ret;
+
+  if (!order) {
+    ERR_clear_error();
+    return 0;
+  }
+  group = EC_KEY_get0_group(pkey->pkey.ec);
+  if (!EC_GROUP_get_order(group, order, NULL)) {
+    ERR_clear_error();
+    return 0;
+  }
+
+  ret = BN_num_bits(order);
+  BN_free(order);
+  return ret;
+}
+
+static int ec_missing_parameters(const EVP_PKEY *pkey) {
+  return EC_KEY_get0_group(pkey->pkey.ec) == NULL;
+}
+
+static int ec_copy_parameters(EVP_PKEY *to, const EVP_PKEY *from) {
+  EC_GROUP *group = EC_GROUP_dup(EC_KEY_get0_group(from->pkey.ec));
+  if (group == NULL ||
+      EC_KEY_set_group(to->pkey.ec, group) == 0) {
+    return 0;
+  }
+  EC_GROUP_free(group);
+  return 1;
+}
+
+static int ec_cmp_parameters(const EVP_PKEY *a, const EVP_PKEY *b) {
+  const EC_GROUP *group_a = EC_KEY_get0_group(a->pkey.ec),
+                 *group_b = EC_KEY_get0_group(b->pkey.ec);
+  return EC_GROUP_cmp(group_a, group_b);
+}
+
+static void int_ec_free(EVP_PKEY *pkey) { EC_KEY_free(pkey->pkey.ec); }
+
+static int do_EC_KEY_print(BIO *bp, const EC_KEY *x, int off, int ktype) {
+  uint8_t *buffer = NULL;
+  const char *ecstr;
+  size_t buf_len = 0, i;
+  int ret = 0, reason = ERR_R_BIO_LIB;
+  BIGNUM *order = NULL;
+  BN_CTX *ctx = NULL;
+  const EC_GROUP *group;
+  const EC_POINT *public_key;
+  const BIGNUM *priv_key;
+  uint8_t *pub_key_bytes = NULL;
+  size_t pub_key_bytes_len = 0;
+
+  if (x == NULL || (group = EC_KEY_get0_group(x)) == NULL) {
+    reason = ERR_R_PASSED_NULL_PARAMETER;
+    goto err;
+  }
+
+  ctx = BN_CTX_new();
+  if (ctx == NULL) {
+    reason = ERR_R_MALLOC_FAILURE;
+    goto err;
+  }
+
+  if (ktype > 0) {
+    public_key = EC_KEY_get0_public_key(x);
+    pub_key_bytes_len = EC_POINT_point2oct(
+        group, public_key, EC_KEY_get_conv_form(x), NULL, 0, ctx);
+    if (pub_key_bytes_len == 0) {
+      reason = ERR_R_MALLOC_FAILURE;
+      goto err;
+    }
+    pub_key_bytes = OPENSSL_malloc(pub_key_bytes_len);
+    if (pub_key_bytes == NULL) {
+      reason = ERR_R_MALLOC_FAILURE;
+      goto err;
+    }
+    pub_key_bytes_len =
+        EC_POINT_point2oct(group, public_key, EC_KEY_get_conv_form(x),
+                           pub_key_bytes, pub_key_bytes_len, ctx);
+    if (pub_key_bytes_len == 0) {
+      reason = ERR_R_MALLOC_FAILURE;
+      goto err;
+    }
+    buf_len = pub_key_bytes_len;
+  }
+
+  if (ktype == 2) {
+    priv_key = EC_KEY_get0_private_key(x);
+    if (priv_key && (i = (size_t)BN_num_bytes(priv_key)) > buf_len)
+      buf_len = i;
+  } else
+    priv_key = NULL;
+
+  if (ktype > 0) {
+    buf_len += 10;
+    if ((buffer = OPENSSL_malloc(buf_len)) == NULL) {
+      reason = ERR_R_MALLOC_FAILURE;
+      goto err;
+    }
+  }
+  if (ktype == 2)
+    ecstr = "Private-Key";
+  else if (ktype == 1)
+    ecstr = "Public-Key";
+  else
+    ecstr = "ECDSA-Parameters";
+
+  if (!BIO_indent(bp, off, 128))
+    goto err;
+  if ((order = BN_new()) == NULL)
+    goto err;
+  if (!EC_GROUP_get_order(group, order, NULL))
+    goto err;
+  if (BIO_printf(bp, "%s: (%d bit)\n", ecstr, BN_num_bits(order)) <= 0)
+    goto err;
+
+  if ((priv_key != NULL) && !ASN1_bn_print(bp, "priv:", priv_key, buffer, off))
+    goto err;
+  if (pub_key_bytes != NULL) {
+    BIO_hexdump(bp, pub_key_bytes, pub_key_bytes_len, off);
+  }
+  /* TODO(fork): implement */
+  /*
+  if (!ECPKParameters_print(bp, group, off))
+    goto err; */
+  ret = 1;
+
+err:
+  if (!ret)
+    OPENSSL_PUT_ERROR(EVP, do_EC_KEY_print, reason);
+  if (pub_key_bytes)
+    OPENSSL_free(pub_key_bytes);
+  if (order)
+    BN_free(order);
+  if (ctx)
+    BN_CTX_free(ctx);
+  if (buffer != NULL)
+    OPENSSL_free(buffer);
+  return ret;
+}
+
+static int eckey_param_decode(EVP_PKEY *pkey, const uint8_t **pder,
+                              int derlen) {
+  EC_KEY *eckey;
+  if (!(eckey = d2i_ECParameters(NULL, pder, derlen))) {
+    OPENSSL_PUT_ERROR(EVP, eckey_param_decode, ERR_R_EC_LIB);
+    return 0;
+  }
+  EVP_PKEY_assign_EC_KEY(pkey, eckey);
+  return 1;
+}
+
+static int eckey_param_encode(const EVP_PKEY *pkey, uint8_t **pder) {
+  return i2d_ECParameters(pkey->pkey.ec, pder);
+}
+
+static int eckey_param_print(BIO *bp, const EVP_PKEY *pkey, int indent,
+                             ASN1_PCTX *ctx) {
+  return do_EC_KEY_print(bp, pkey->pkey.ec, indent, 0);
+}
+
+static int eckey_pub_print(BIO *bp, const EVP_PKEY *pkey, int indent,
+                           ASN1_PCTX *ctx) {
+  return do_EC_KEY_print(bp, pkey->pkey.ec, indent, 1);
+}
+
+
+static int eckey_priv_print(BIO *bp, const EVP_PKEY *pkey, int indent,
+                            ASN1_PCTX *ctx) {
+  return do_EC_KEY_print(bp, pkey->pkey.ec, indent, 2);
+}
+
+static int old_ec_priv_decode(EVP_PKEY *pkey, const uint8_t **pder,
+                              int derlen) {
+  EC_KEY *ec;
+  if (!(ec = d2i_ECPrivateKey(NULL, pder, derlen))) {
+    OPENSSL_PUT_ERROR(EVP, old_ec_priv_decode, EVP_R_DECODE_ERROR);
+    return 0;
+  }
+  EVP_PKEY_assign_EC_KEY(pkey, ec);
+  return 1;
+}
+
+static int old_ec_priv_encode(const EVP_PKEY *pkey, uint8_t **pder) {
+  return i2d_ECPrivateKey(pkey->pkey.ec, pder);
+}
+
+static int ec_pkey_ctrl(EVP_PKEY *pkey, int op, long arg1, void *arg2) {
+  switch (op) {
+    case ASN1_PKEY_CTRL_DEFAULT_MD_NID:
+      *(int *)arg2 = NID_sha1;
+      return 2;
+
+    default:
+      return -2;
+  }
+}
+
+const EVP_PKEY_ASN1_METHOD ec_asn1_meth = {
+  EVP_PKEY_EC,
+  EVP_PKEY_EC,
+  0,
+  "EC",
+  "OpenSSL EC algorithm",
+
+  eckey_pub_decode,
+  eckey_pub_encode,
+  eckey_pub_cmp,
+  eckey_pub_print,
+
+  eckey_priv_decode,
+  eckey_priv_encode,
+  eckey_priv_print,
+
+  int_ec_size,
+  ec_bits,
+
+  eckey_param_decode,
+  eckey_param_encode,
+  ec_missing_parameters,
+  ec_copy_parameters,
+  ec_cmp_parameters,
+  eckey_param_print,
+  0,
+
+  int_ec_free,
+  ec_pkey_ctrl,
+  old_ec_priv_decode,
+  old_ec_priv_encode
+};
diff --git a/crypto/evp/p_hmac.c b/crypto/evp/p_hmac.c
new file mode 100644
index 0000000..b55db7a
--- /dev/null
+++ b/crypto/evp/p_hmac.c
@@ -0,0 +1,215 @@
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project 2007.
+ */
+/* ====================================================================
+ * Copyright (c) 2007 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    licensing@OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com). */
+
+#include <openssl/evp.h>
+
+#include <openssl/asn1.h>
+#include <openssl/hmac.h>
+#include <openssl/mem.h>
+#include <openssl/obj.h>
+
+#include "internal.h"
+
+
+typedef struct {
+  const EVP_MD *md;       /* MD for HMAC use */
+  ASN1_OCTET_STRING ktmp; /* Temp storage for key */
+  HMAC_CTX ctx;
+} HMAC_PKEY_CTX;
+
+static int pkey_hmac_init(EVP_PKEY_CTX *ctx) {
+  HMAC_PKEY_CTX *hctx;
+  hctx = OPENSSL_malloc(sizeof(HMAC_PKEY_CTX));
+  if (!hctx) {
+    return 0;
+  }
+  memset(hctx, 0, sizeof(HMAC_PKEY_CTX));
+  hctx->ktmp.type = V_ASN1_OCTET_STRING;
+  HMAC_CTX_init(&hctx->ctx);
+
+  ctx->data = hctx;
+
+  return 1;
+}
+
+static int pkey_hmac_copy(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src) {
+  HMAC_PKEY_CTX *sctx, *dctx;
+  if (!pkey_hmac_init(dst)) {
+    return 0;
+  }
+  sctx = src->data;
+  dctx = dst->data;
+  dctx->md = sctx->md;
+  HMAC_CTX_init(&dctx->ctx);
+  if (!HMAC_CTX_copy(&dctx->ctx, &sctx->ctx)) {
+    return 0;
+  }
+  if (sctx->ktmp.data) {
+    if (!ASN1_OCTET_STRING_set(&dctx->ktmp, sctx->ktmp.data,
+                               sctx->ktmp.length)) {
+      return 0;
+    }
+  }
+  return 1;
+}
+
+static void pkey_hmac_cleanup(EVP_PKEY_CTX *ctx) {
+  HMAC_PKEY_CTX *hctx = ctx->data;
+
+  HMAC_CTX_cleanup(&hctx->ctx);
+  if (hctx->ktmp.data) {
+    if (hctx->ktmp.length) {
+      OPENSSL_cleanse(hctx->ktmp.data, hctx->ktmp.length);
+    }
+    OPENSSL_free(hctx->ktmp.data);
+    hctx->ktmp.data = NULL;
+  }
+  OPENSSL_free(hctx);
+}
+
+static int pkey_hmac_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) {
+  ASN1_OCTET_STRING *hkey = NULL;
+  HMAC_PKEY_CTX *hctx = ctx->data;
+
+  if (!hctx->ktmp.data) {
+    return 0;
+  }
+  hkey = ASN1_OCTET_STRING_dup(&hctx->ktmp);
+  if (!hkey) {
+    return 0;
+  }
+  EVP_PKEY_assign(pkey, EVP_PKEY_HMAC, hkey);
+
+  return 1;
+}
+
+static int int_update(EVP_MD_CTX *ctx, const void *data, size_t count) {
+  HMAC_PKEY_CTX *hctx = ctx->pctx->data;
+  return HMAC_Update(&hctx->ctx, data, count);
+}
+
+static int hmac_signctx_init(EVP_PKEY_CTX *ctx, EVP_MD_CTX *mctx) {
+  HMAC_PKEY_CTX *hctx = ctx->data;
+
+  HMAC_CTX_set_flags(&hctx->ctx, mctx->flags & ~EVP_MD_CTX_FLAG_NO_INIT);
+  EVP_MD_CTX_set_flags(mctx, EVP_MD_CTX_FLAG_NO_INIT);
+  mctx->update = int_update;
+  return 1;
+}
+
+static int hmac_signctx(EVP_PKEY_CTX *ctx, unsigned char *sig, size_t *siglen,
+                        EVP_MD_CTX *mctx) {
+  unsigned int hlen;
+  HMAC_PKEY_CTX *hctx = ctx->data;
+  int l = EVP_MD_CTX_size(mctx);
+
+  if (l < 0) {
+    return 0;
+  }
+  *siglen = l;
+  if (!sig) {
+    return 1;
+  }
+
+  if (!HMAC_Final(&hctx->ctx, sig, &hlen)) {
+    return 0;
+  }
+  *siglen = (size_t)hlen;
+  return 1;
+}
+
+static int pkey_hmac_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2) {
+  HMAC_PKEY_CTX *hctx = ctx->data;
+  ASN1_OCTET_STRING *key;
+
+  switch (type) {
+    case EVP_PKEY_CTRL_SET_MAC_KEY:
+      if ((!p2 && p1 > 0) || (p1 < -1)) {
+        return 0;
+      }
+      if (!ASN1_OCTET_STRING_set(&hctx->ktmp, p2, p1)) {
+        return 0;
+      }
+      break;
+
+    case EVP_PKEY_CTRL_MD:
+      hctx->md = p2;
+      break;
+
+    case EVP_PKEY_CTRL_DIGESTINIT:
+      key = (ASN1_OCTET_STRING *)ctx->pkey->pkey.ptr;
+      if (!HMAC_Init_ex(&hctx->ctx, key->data, key->length, hctx->md,
+                        ctx->engine)) {
+        return 0;
+      }
+      break;
+
+    default:
+      return -2;
+  }
+  return 1;
+}
+
+const EVP_PKEY_METHOD hmac_pkey_meth = {
+    EVP_PKEY_HMAC,          0 /* flags */,        pkey_hmac_init,
+    pkey_hmac_copy,         pkey_hmac_cleanup,    0 /* paramgen_init */,
+    0 /* paramgen */,       0 /* keygen_init */,  pkey_hmac_keygen,
+    0 /* sign_init */,      0 /* sign */,         0 /* verify_init */,
+    0 /* verify */,         hmac_signctx_init,    hmac_signctx,
+    0 /* verifyctx_init */, 0 /* verifyctx */,    0 /* encrypt_init */,
+    0 /* encrypt */,        0 /* decrypt_init */, 0 /* decrypt */,
+    0 /* derive_init */,    0 /* derive */,       pkey_hmac_ctrl,
+    0,
+};
diff --git a/crypto/evp/p_hmac_asn1.c b/crypto/evp/p_hmac_asn1.c
new file mode 100644
index 0000000..cabd737
--- /dev/null
+++ b/crypto/evp/p_hmac_asn1.c
@@ -0,0 +1,99 @@
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project 2007.
+ */
+/* ====================================================================
+ * Copyright (c) 2007 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    licensing@OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com). */
+
+#include <openssl/evp.h>
+
+#include <openssl/asn1.h>
+#include <openssl/digest.h>
+#include <openssl/mem.h>
+#include <openssl/obj.h>
+
+#include "internal.h"
+
+
+static int hmac_size(const EVP_PKEY *pkey) { return EVP_MAX_MD_SIZE; }
+
+static void hmac_key_free(EVP_PKEY *pkey) {
+  ASN1_OCTET_STRING *os = (ASN1_OCTET_STRING *)pkey->pkey.ptr;
+  if (os) {
+    if (os->data) {
+      OPENSSL_cleanse(os->data, os->length);
+    }
+    ASN1_OCTET_STRING_free(os);
+  }
+}
+
+static int hmac_pkey_ctrl(EVP_PKEY *pkey, int op, long arg1, void *arg2) {
+  switch (op) {
+    case ASN1_PKEY_CTRL_DEFAULT_MD_NID:
+      *(int *)arg2 = NID_sha1;
+      return 1;
+
+    default:
+      return -2;
+  }
+}
+
+const EVP_PKEY_ASN1_METHOD hmac_asn1_meth = {
+    EVP_PKEY_HMAC,       EVP_PKEY_HMAC,         0 /* flags */,
+    "HMAC",              "OpenSSL HMAC method", 0 /* pub_decode */,
+    0 /* pub_encode */,  0 /* pub_cmp */,       0 /* pub_print */,
+    0 /*priv_decode */,  0 /* priv_encode */,   0 /* priv_print */,
+    hmac_size,           0 /* pkey_bits */,     0 /* param_decode */,
+    0 /* param_encode*/, 0 /* param_missing*/,  0 /* param_copy*/,
+    0 /* param_cmp*/,    0 /* param_print*/,    0 /* sig_print*/,
+    hmac_key_free,       hmac_pkey_ctrl,        0 /* old_priv_decode */,
+    0 /* old_priv_encode */
+};
diff --git a/crypto/evp/p_rsa.c b/crypto/evp/p_rsa.c
new file mode 100644
index 0000000..2fab371
--- /dev/null
+++ b/crypto/evp/p_rsa.c
@@ -0,0 +1,596 @@
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project 2006.
+ */
+/* ====================================================================
+ * Copyright (c) 2006 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    licensing@OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com). */
+
+#include <openssl/evp.h>
+
+#include <openssl/bn.h>
+#include <openssl/buf.h>
+#include <openssl/digest.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+#include <openssl/obj.h>
+#include <openssl/rsa.h>
+
+#include "../rsa/internal.h"
+#include "internal.h"
+
+
+typedef struct {
+  /* Key gen parameters */
+  int nbits;
+  BIGNUM *pub_exp;
+  /* RSA padding mode */
+  int pad_mode;
+  /* message digest */
+  const EVP_MD *md;
+  /* message digest for MGF1 */
+  const EVP_MD *mgf1md;
+  /* PSS salt length */
+  int saltlen;
+  /* tbuf is a buffer which is either NULL, or is the size of the RSA modulus.
+   * It's used to store the output of RSA operations. */
+  uint8_t *tbuf;
+  /* OAEP label */
+  uint8_t *oaep_label;
+  size_t oaep_labellen;
+} RSA_PKEY_CTX;
+
+static int pkey_rsa_init(EVP_PKEY_CTX *ctx) {
+  RSA_PKEY_CTX *rctx;
+  rctx = OPENSSL_malloc(sizeof(RSA_PKEY_CTX));
+  if (!rctx) {
+    return 0;
+  }
+  memset(rctx, 0, sizeof(RSA_PKEY_CTX));
+
+  rctx->nbits = 2048;
+  rctx->pad_mode = RSA_PKCS1_PADDING;
+  rctx->saltlen = -2;
+
+  ctx->data = rctx;
+
+  return 1;
+}
+
+static int pkey_rsa_copy(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src) {
+  RSA_PKEY_CTX *dctx, *sctx;
+  if (!pkey_rsa_init(dst)) {
+    return 0;
+  }
+  sctx = src->data;
+  dctx = dst->data;
+  dctx->nbits = sctx->nbits;
+  if (sctx->pub_exp) {
+    dctx->pub_exp = BN_dup(sctx->pub_exp);
+    if (!dctx->pub_exp) {
+      return 0;
+    }
+  }
+
+  dctx->pad_mode = sctx->pad_mode;
+  dctx->md = sctx->md;
+  dctx->mgf1md = sctx->mgf1md;
+  if (sctx->oaep_label) {
+    if (dctx->oaep_label) {
+      OPENSSL_free(dctx->oaep_label);
+    }
+    dctx->oaep_label = BUF_memdup(sctx->oaep_label, sctx->oaep_labellen);
+    if (!dctx->oaep_label) {
+      return 0;
+    }
+    dctx->oaep_labellen = sctx->oaep_labellen;
+  }
+
+  return 1;
+}
+
+static void pkey_rsa_cleanup(EVP_PKEY_CTX *ctx) {
+  RSA_PKEY_CTX *rctx = ctx->data;
+
+  if (rctx == NULL) {
+    return;
+  }
+
+  if (rctx->pub_exp) {
+    BN_free(rctx->pub_exp);
+  }
+  if (rctx->tbuf) {
+    OPENSSL_free(rctx->tbuf);
+  }
+  if (rctx->oaep_label) {
+    OPENSSL_free(rctx->oaep_label);
+  }
+  OPENSSL_free(rctx);
+}
+
+static int setup_tbuf(RSA_PKEY_CTX *ctx, EVP_PKEY_CTX *pk) {
+  if (ctx->tbuf) {
+    return 1;
+  }
+  ctx->tbuf = OPENSSL_malloc(EVP_PKEY_size(pk->pkey));
+  if (!ctx->tbuf) {
+    return 0;
+  }
+  return 1;
+}
+
+static int pkey_rsa_sign(EVP_PKEY_CTX *ctx, uint8_t *sig, size_t *siglen,
+                         const uint8_t *tbs, size_t tbslen) {
+  int ret;
+  RSA_PKEY_CTX *rctx = ctx->data;
+  RSA *rsa = ctx->pkey->pkey.rsa;
+
+  if (rctx->md) {
+    if (tbslen != EVP_MD_size(rctx->md)) {
+      OPENSSL_PUT_ERROR(EVP, pkey_rsa_sign, EVP_R_INVALID_DIGEST_LENGTH);
+      return -1;
+    }
+
+    if (EVP_MD_type(rctx->md) == NID_mdc2) {
+      OPENSSL_PUT_ERROR(EVP, pkey_rsa_sign, EVP_R_NO_MDC2_SUPPORT);
+      ret = -1;
+    } else if (rctx->pad_mode == RSA_PKCS1_PADDING) {
+      unsigned int sltmp;
+      ret = RSA_sign(EVP_MD_type(rctx->md), tbs, tbslen, sig, &sltmp, rsa);
+      if (ret <= 0) {
+        return ret;
+      }
+      ret = sltmp;
+    } else if (rctx->pad_mode == RSA_PKCS1_PSS_PADDING) {
+      if (!setup_tbuf(rctx, ctx) ||
+          !RSA_padding_add_PKCS1_PSS_mgf1(rsa, rctx->tbuf, tbs, rctx->md,
+                                          rctx->mgf1md, rctx->saltlen)) {
+        return -1;
+      }
+      /* TODO(fork): don't use private_encrypt. */
+      ret = RSA_private_encrypt(RSA_size(rsa), rctx->tbuf, sig, rsa,
+                                RSA_NO_PADDING);
+    } else {
+      return -1;
+    }
+  } else {
+    /* TODO(fork): don't use private_encrypt. */
+    ret = RSA_private_encrypt(tbslen, tbs, sig, ctx->pkey->pkey.rsa,
+                              rctx->pad_mode);
+  }
+
+  if (ret < 0) {
+    return ret;
+  }
+  *siglen = ret;
+
+  return 1;
+}
+
+static int pkey_rsa_verify(EVP_PKEY_CTX *ctx, const uint8_t *sig,
+                           size_t siglen, const uint8_t *tbs,
+                           size_t tbslen) {
+  RSA_PKEY_CTX *rctx = ctx->data;
+  RSA *rsa = ctx->pkey->pkey.rsa;
+  size_t rslen;
+
+  if (rctx->md) {
+    if (rctx->pad_mode == RSA_PKCS1_PADDING) {
+      return RSA_verify(EVP_MD_type(rctx->md), tbs, tbslen, sig, siglen, rsa);
+    }
+
+    if (rctx->pad_mode == RSA_PKCS1_PSS_PADDING) {
+      int ret;
+      if (!setup_tbuf(rctx, ctx)) {
+        return -1;
+      }
+      /* TODO(fork): don't use public_decrypt. */
+      ret = RSA_public_decrypt(siglen, sig, rctx->tbuf, rsa, RSA_NO_PADDING);
+      if (ret <= 0) {
+        return 0;
+      }
+      ret = RSA_verify_PKCS1_PSS_mgf1(rsa, tbs, rctx->md, rctx->mgf1md,
+                                      rctx->tbuf, rctx->saltlen);
+      if (ret <= 0) {
+        return 0;
+      }
+      return 1;
+    } else {
+      return -1;
+    }
+  } else {
+    if (!setup_tbuf(rctx, ctx)) {
+      return -1;
+    }
+    rslen = RSA_public_decrypt(siglen, sig, rctx->tbuf, rsa, rctx->pad_mode);
+    if (rslen == 0) {
+      return 0;
+    }
+  }
+
+  if (rslen != tbslen || CRYPTO_memcmp(tbs, rctx->tbuf, rslen) != 0) {
+    return 0;
+  }
+
+  return 1;
+}
+
+static int pkey_rsa_encrypt(EVP_PKEY_CTX *ctx, uint8_t *out, size_t *outlen,
+                            const uint8_t *in, size_t inlen) {
+  int ret;
+  RSA_PKEY_CTX *rctx = ctx->data;
+
+  if (rctx->pad_mode == RSA_PKCS1_OAEP_PADDING) {
+    int klen = RSA_size(ctx->pkey->pkey.rsa);
+    if (!setup_tbuf(rctx, ctx)) {
+      return -1;
+    }
+    if (!RSA_padding_add_PKCS1_OAEP_mgf1(rctx->tbuf, klen, in, inlen,
+                                         rctx->oaep_label, rctx->oaep_labellen,
+                                         rctx->md, rctx->mgf1md)) {
+      return -1;
+    }
+    ret = RSA_public_encrypt(klen, rctx->tbuf, out, ctx->pkey->pkey.rsa,
+                             RSA_NO_PADDING);
+  } else {
+    ret =
+        RSA_public_encrypt(inlen, in, out, ctx->pkey->pkey.rsa, rctx->pad_mode);
+  }
+
+  if (ret < 0) {
+    return ret;
+  }
+  *outlen = ret;
+
+  return 1;
+}
+
+static int pkey_rsa_decrypt(EVP_PKEY_CTX *ctx, uint8_t *out,
+                            size_t *outlen, const uint8_t *in,
+                            size_t inlen) {
+  int ret;
+  RSA_PKEY_CTX *rctx = ctx->data;
+
+  if (rctx->pad_mode == RSA_PKCS1_OAEP_PADDING) {
+    int i;
+    if (!setup_tbuf(rctx, ctx)) {
+      return -1;
+    }
+    ret = RSA_private_decrypt(inlen, in, rctx->tbuf, ctx->pkey->pkey.rsa,
+                              RSA_NO_PADDING);
+    if (ret <= 0) {
+      return ret;
+    }
+    for (i = 0; i < ret; i++) {
+      if (rctx->tbuf[i]) {
+        break;
+      }
+    }
+    ret = RSA_padding_check_PKCS1_OAEP_mgf1(
+        out, ret, rctx->tbuf + i, ret - i, ret, rctx->oaep_label,
+        rctx->oaep_labellen, rctx->md, rctx->mgf1md);
+  } else {
+    ret = RSA_private_decrypt(inlen, in, out, ctx->pkey->pkey.rsa,
+                              rctx->pad_mode);
+  }
+
+  if (ret < 0) {
+    return ret;
+  }
+  *outlen = ret;
+
+  return 1;
+}
+
+static int check_padding_md(const EVP_MD *md, int padding) {
+  if (!md) {
+    return 1;
+  }
+
+  if (padding == RSA_NO_PADDING) {
+    OPENSSL_PUT_ERROR(EVP, check_padding_md, EVP_R_INVALID_PADDING_MODE);
+    return 0;
+  }
+
+  return 1;
+}
+
+static int is_known_padding(int padding_mode) {
+  switch (padding_mode) {
+    case RSA_PKCS1_PADDING:
+    case RSA_SSLV23_PADDING:
+    case RSA_NO_PADDING:
+    case RSA_PKCS1_OAEP_PADDING:
+    case RSA_PKCS1_PSS_PADDING:
+      return 1;
+    default:
+      return 0;
+  }
+}
+
+static int pkey_rsa_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2) {
+  RSA_PKEY_CTX *rctx = ctx->data;
+  switch (type) {
+    case EVP_PKEY_CTRL_RSA_PADDING:
+      if (!is_known_padding(p1) || !check_padding_md(rctx->md, p1) ||
+          (p1 == RSA_PKCS1_PSS_PADDING &&
+           0 == (ctx->operation & (EVP_PKEY_OP_SIGN | EVP_PKEY_OP_VERIFY))) ||
+          (p1 == RSA_PKCS1_OAEP_PADDING &&
+           0 == (ctx->operation & EVP_PKEY_OP_TYPE_CRYPT))) {
+        OPENSSL_PUT_ERROR(EVP, pkey_rsa_ctrl,
+                          EVP_R_ILLEGAL_OR_UNSUPPORTED_PADDING_MODE);
+        return -2;
+      }
+      if ((p1 == RSA_PKCS1_PSS_PADDING || p1 == RSA_PKCS1_OAEP_PADDING) &&
+          rctx->md == NULL) {
+        rctx->md = EVP_sha1();
+      }
+      rctx->pad_mode = p1;
+      return 1;
+
+    case EVP_PKEY_CTRL_GET_RSA_PADDING:
+      *(int *)p2 = rctx->pad_mode;
+      return 1;
+
+    case EVP_PKEY_CTRL_RSA_PSS_SALTLEN:
+    case EVP_PKEY_CTRL_GET_RSA_PSS_SALTLEN:
+      if (rctx->pad_mode != RSA_PKCS1_PSS_PADDING) {
+        OPENSSL_PUT_ERROR(EVP, pkey_rsa_ctrl, EVP_R_INVALID_PSS_SALTLEN);
+        return -2;
+      }
+      if (type == EVP_PKEY_CTRL_GET_RSA_PSS_SALTLEN) {
+        *(int *)p2 = rctx->saltlen;
+      } else {
+        if (p1 < -2) {
+          return -2;
+        }
+        rctx->saltlen = p1;
+      }
+      return 1;
+
+    case EVP_PKEY_CTRL_RSA_KEYGEN_BITS:
+      if (p1 < 256) {
+        OPENSSL_PUT_ERROR(EVP, pkey_rsa_ctrl, EVP_R_INVALID_KEYBITS);
+        return -2;
+      }
+      rctx->nbits = p1;
+      return 1;
+
+    case EVP_PKEY_CTRL_RSA_KEYGEN_PUBEXP:
+      if (!p2) {
+        return -2;
+      }
+      BN_free(rctx->pub_exp);
+      rctx->pub_exp = p2;
+      return 1;
+
+    case EVP_PKEY_CTRL_RSA_OAEP_MD:
+    case EVP_PKEY_CTRL_GET_RSA_OAEP_MD:
+      if (rctx->pad_mode != RSA_PKCS1_OAEP_PADDING) {
+        OPENSSL_PUT_ERROR(EVP, pkey_rsa_ctrl, EVP_R_INVALID_PADDING_MODE);
+        return -2;
+      }
+      if (type == EVP_PKEY_CTRL_GET_RSA_OAEP_MD) {
+        *(const EVP_MD **)p2 = rctx->md;
+      } else {
+        rctx->md = p2;
+      }
+      return 1;
+
+    case EVP_PKEY_CTRL_MD:
+      if (!check_padding_md(p2, rctx->pad_mode)) {
+        return 0;
+      }
+      rctx->md = p2;
+      return 1;
+
+    case EVP_PKEY_CTRL_GET_MD:
+      *(const EVP_MD **)p2 = rctx->md;
+      return 1;
+
+    case EVP_PKEY_CTRL_RSA_MGF1_MD:
+    case EVP_PKEY_CTRL_GET_RSA_MGF1_MD:
+      if (rctx->pad_mode != RSA_PKCS1_PSS_PADDING &&
+          rctx->pad_mode != RSA_PKCS1_OAEP_PADDING) {
+        OPENSSL_PUT_ERROR(EVP, pkey_rsa_ctrl, EVP_R_INVALID_MGF1_MD);
+        return -2;
+      }
+      if (type == EVP_PKEY_CTRL_GET_RSA_MGF1_MD) {
+        if (rctx->mgf1md) {
+          *(const EVP_MD **)p2 = rctx->mgf1md;
+        } else {
+          *(const EVP_MD **)p2 = rctx->md;
+        }
+      } else {
+        rctx->mgf1md = p2;
+      }
+      return 1;
+
+    case EVP_PKEY_CTRL_RSA_OAEP_LABEL:
+      if (rctx->pad_mode != RSA_PKCS1_OAEP_PADDING) {
+        OPENSSL_PUT_ERROR(EVP, pkey_rsa_ctrl, EVP_R_INVALID_PADDING_MODE);
+        return -2;
+      }
+      if (rctx->oaep_label) {
+        OPENSSL_free(rctx->oaep_label);
+      }
+      if (p2 && p1 > 0) {
+        /* TODO(fork): this seems wrong. Shouldn't it take a copy of the
+         * buffer? */
+        rctx->oaep_label = p2;
+        rctx->oaep_labellen = p1;
+      } else {
+        rctx->oaep_label = NULL;
+        rctx->oaep_labellen = 0;
+      }
+      return 1;
+
+    case EVP_PKEY_CTRL_GET_RSA_OAEP_LABEL:
+      if (rctx->pad_mode != RSA_PKCS1_OAEP_PADDING) {
+        OPENSSL_PUT_ERROR(EVP, pkey_rsa_ctrl, EVP_R_INVALID_PADDING_MODE);
+        return -2;
+      }
+      *(uint8_t **)p2 = rctx->oaep_label;
+      return rctx->oaep_labellen;
+
+    case EVP_PKEY_CTRL_DIGESTINIT:
+      return 1;
+
+    default:
+      return -2;
+  }
+}
+
+static int pkey_rsa_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) {
+  RSA *rsa = NULL;
+  RSA_PKEY_CTX *rctx = ctx->data;
+
+  int ret;
+  if (!rctx->pub_exp) {
+    rctx->pub_exp = BN_new();
+    if (!rctx->pub_exp || !BN_set_word(rctx->pub_exp, RSA_F4))
+      return 0;
+  }
+  rsa = RSA_new();
+  if (!rsa) {
+    return 0;
+  }
+
+  ret = RSA_generate_key_ex(rsa, rctx->nbits, rctx->pub_exp, NULL);
+  if (ret > 0) {
+    EVP_PKEY_assign_RSA(pkey, rsa);
+  } else {
+    RSA_free(rsa);
+  }
+  return ret;
+}
+
+const EVP_PKEY_METHOD rsa_pkey_meth = {
+    EVP_PKEY_RSA,        EVP_PKEY_FLAG_AUTOARGLEN, 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,                        0,
+    0,                   0,                        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) {
+  return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, -1, EVP_PKEY_CTRL_RSA_PADDING,
+                           padding, NULL);
+}
+
+int EVP_PKEY_CTX_get_rsa_padding(EVP_PKEY_CTX *ctx, int *out_padding) {
+  return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, -1, EVP_PKEY_CTRL_GET_RSA_PADDING,
+                           0, out_padding);
+}
+
+int EVP_PKEY_CTX_set_rsa_pss_saltlen(EVP_PKEY_CTX *ctx, int salt_len) {
+  return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA,
+                           (EVP_PKEY_OP_SIGN | EVP_PKEY_OP_VERIFY),
+                           EVP_PKEY_CTRL_RSA_PSS_SALTLEN, salt_len, NULL);
+}
+
+int EVP_PKEY_CTX_get_rsa_pss_saltlen(EVP_PKEY_CTX *ctx, int *out_salt_len) {
+  return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA,
+                           (EVP_PKEY_OP_SIGN | EVP_PKEY_OP_VERIFY),
+                           EVP_PKEY_CTRL_GET_RSA_PSS_SALTLEN, 0, out_salt_len);
+}
+
+int EVP_PKEY_CTX_set_rsa_keygen_bits(EVP_PKEY_CTX *ctx, int bits) {
+  return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, EVP_PKEY_OP_KEYGEN,
+                           EVP_PKEY_CTRL_RSA_KEYGEN_BITS, bits, NULL);
+}
+
+int EVP_PKEY_CTX_set_rsa_keygen_pubexp(EVP_PKEY_CTX *ctx, BIGNUM *e) {
+  return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, EVP_PKEY_OP_KEYGEN,
+                           EVP_PKEY_CTRL_RSA_KEYGEN_PUBEXP, 0, e);
+}
+
+int EVP_PKEY_CTX_set_rsa_oaep_md(EVP_PKEY_CTX *ctx, const EVP_MD *md) {
+  return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, EVP_PKEY_OP_TYPE_CRYPT,
+                           EVP_PKEY_CTRL_RSA_OAEP_MD, 0, (void *)md);
+}
+
+int EVP_PKEY_CTX_get_rsa_oaep_md(EVP_PKEY_CTX *ctx, const EVP_MD **out_md) {
+  return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, EVP_PKEY_OP_TYPE_CRYPT,
+                           EVP_PKEY_CTRL_GET_RSA_OAEP_MD, 0, (void*) out_md);
+}
+
+int EVP_PKEY_CTX_set_rsa_mgf1_md(EVP_PKEY_CTX *ctx, const EVP_MD *md) {
+  return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA,
+                           EVP_PKEY_OP_TYPE_SIG | EVP_PKEY_OP_TYPE_CRYPT,
+                           EVP_PKEY_CTRL_RSA_MGF1_MD, 0, (void*) md);
+}
+
+int EVP_PKEY_CTX_get_rsa_mgf1_md(EVP_PKEY_CTX *ctx, const EVP_MD **out_md) {
+  return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA,
+                           EVP_PKEY_OP_TYPE_SIG | EVP_PKEY_OP_TYPE_CRYPT,
+                           EVP_PKEY_CTRL_GET_RSA_MGF1_MD, 0, (void*) out_md);
+}
+
+int EVP_PKEY_CTX_set0_rsa_oaep_label(EVP_PKEY_CTX *ctx, const uint8_t *label,
+                                     size_t label_len) {
+  int label_len_int = label_len;
+  if (((size_t) label_len_int) != label_len) {
+    return -2;
+  }
+
+  return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, EVP_PKEY_OP_TYPE_CRYPT,
+                           EVP_PKEY_CTRL_RSA_OAEP_LABEL, label_len,
+                           (void *)label);
+}
+
+int EVP_PKEY_CTX_get0_rsa_oaep_label(EVP_PKEY_CTX *ctx,
+                                     const uint8_t **out_label) {
+  return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, EVP_PKEY_OP_TYPE_CRYPT,
+                           EVP_PKEY_CTRL_GET_RSA_OAEP_LABEL, 0, (void *) out_label);
+}
diff --git a/crypto/evp/p_rsa_asn1.c b/crypto/evp/p_rsa_asn1.c
new file mode 100644
index 0000000..6b94ed7
--- /dev/null
+++ b/crypto/evp/p_rsa_asn1.c
@@ -0,0 +1,751 @@
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project 2006.
+ */
+/* ====================================================================
+ * Copyright (c) 2006 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    licensing@OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com). */
+
+#include <openssl/evp.h>
+
+#include <openssl/asn1.h>
+#include <openssl/asn1t.h>
+#include <openssl/digest.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+#include <openssl/obj.h>
+#include <openssl/rsa.h>
+#include <openssl/x509.h>
+
+#include "../rsa/internal.h"
+#include "internal.h"
+
+
+static int rsa_pub_encode(X509_PUBKEY *pk, const EVP_PKEY *pkey) {
+  uint8_t *encoded = NULL;
+  int len;
+  len = i2d_RSAPublicKey(pkey->pkey.rsa, &encoded);
+
+  if (len <= 0) {
+    return 0;
+  }
+
+  if (!X509_PUBKEY_set0_param(pk, OBJ_nid2obj(EVP_PKEY_RSA), V_ASN1_NULL, NULL,
+                              encoded, len)) {
+    OPENSSL_free(encoded);
+    return 0;
+  }
+
+  return 1;
+}
+
+static int rsa_pub_decode(EVP_PKEY *pkey, X509_PUBKEY *pubkey) {
+  const uint8_t *p;
+  int pklen;
+  RSA *rsa;
+
+  if (!X509_PUBKEY_get0_param(NULL, &p, &pklen, NULL, pubkey)) {
+    return 0;
+  }
+  rsa = d2i_RSAPublicKey(NULL, &p, pklen);
+  if (rsa == NULL) {
+    OPENSSL_PUT_ERROR(EVP, rsa_pub_decode, ERR_R_RSA_LIB);
+    return 0;
+  }
+  EVP_PKEY_assign_RSA(pkey, rsa);
+  return 1;
+}
+
+static int rsa_pub_cmp(const EVP_PKEY *a, const EVP_PKEY *b) {
+  return BN_cmp(b->pkey.rsa->n, a->pkey.rsa->n) == 0 &&
+         BN_cmp(b->pkey.rsa->e, a->pkey.rsa->e) == 0;
+}
+
+static int rsa_priv_encode(PKCS8_PRIV_KEY_INFO *p8, const EVP_PKEY *pkey) {
+  uint8_t *rk = NULL;
+  int rklen;
+
+  rklen = i2d_RSAPrivateKey(pkey->pkey.rsa, &rk);
+
+  if (rklen <= 0) {
+    OPENSSL_PUT_ERROR(EVP, rsa_priv_encode, ERR_R_MALLOC_FAILURE);
+    return 0;
+  }
+
+  /* TODO(fork): const correctness in next line. */
+  if (!PKCS8_pkey_set0(p8, (ASN1_OBJECT *)OBJ_nid2obj(NID_rsaEncryption), 0,
+                       V_ASN1_NULL, NULL, rk, rklen)) {
+    OPENSSL_PUT_ERROR(EVP, rsa_priv_encode, ERR_R_MALLOC_FAILURE);
+    return 0;
+  }
+
+  return 1;
+}
+
+static int rsa_priv_decode(EVP_PKEY *pkey, PKCS8_PRIV_KEY_INFO *p8) {
+  const uint8_t *p;
+  int pklen;
+  RSA *rsa;
+
+  if (!PKCS8_pkey_get0(NULL, &p, &pklen, NULL, p8)) {
+    OPENSSL_PUT_ERROR(EVP, rsa_priv_decode, ERR_R_MALLOC_FAILURE);
+    return 0;
+  }
+
+  rsa = d2i_RSAPrivateKey(NULL, &p, pklen);
+  if (rsa == NULL) {
+    OPENSSL_PUT_ERROR(EVP, rsa_priv_decode, ERR_R_RSA_LIB);
+    return 0;
+  }
+
+  EVP_PKEY_assign_RSA(pkey, rsa);
+  return 1;
+}
+
+static int int_rsa_size(const EVP_PKEY *pkey) {
+  return RSA_size(pkey->pkey.rsa);
+}
+
+static int rsa_bits(const EVP_PKEY *pkey) {
+  return BN_num_bits(pkey->pkey.rsa->n);
+}
+
+static void int_rsa_free(EVP_PKEY *pkey) { RSA_free(pkey->pkey.rsa); }
+
+static void update_buflen(const BIGNUM *b, size_t *pbuflen) {
+  size_t i;
+
+  if (!b) {
+    return;
+  }
+
+  i = BN_num_bytes(b);
+  if (*pbuflen < i) {
+    *pbuflen = i;
+  }
+}
+
+static int do_rsa_print(BIO *out, const RSA *rsa, int off,
+                        int include_private) {
+  char *str;
+  const char *s;
+  uint8_t *m = NULL;
+  int ret = 0, mod_len = 0;
+  size_t buf_len = 0;
+
+  update_buflen(rsa->n, &buf_len);
+  update_buflen(rsa->e, &buf_len);
+
+  if (include_private) {
+    update_buflen(rsa->d, &buf_len);
+    update_buflen(rsa->p, &buf_len);
+    update_buflen(rsa->q, &buf_len);
+    update_buflen(rsa->dmp1, &buf_len);
+    update_buflen(rsa->dmq1, &buf_len);
+    update_buflen(rsa->iqmp, &buf_len);
+  }
+
+  m = (uint8_t *)OPENSSL_malloc(buf_len + 10);
+  if (m == NULL) {
+    OPENSSL_PUT_ERROR(EVP, do_rsa_print, ERR_R_MALLOC_FAILURE);
+    goto err;
+  }
+
+  if (rsa->n != NULL) {
+    mod_len = BN_num_bits(rsa->n);
+  }
+
+  if (!BIO_indent(out, off, 128)) {
+    goto err;
+  }
+
+  if (include_private && rsa->d) {
+    if (BIO_printf(out, "Private-Key: (%d bit)\n", mod_len) <= 0) {
+      goto err;
+    }
+    str = "modulus:";
+    s = "publicExponent:";
+  } else {
+    if (BIO_printf(out, "Public-Key: (%d bit)\n", mod_len) <= 0) {
+      goto err;
+    }
+    str = "Modulus:";
+    s = "Exponent:";
+  }
+  if (!ASN1_bn_print(out, str, rsa->n, m, off) ||
+      !ASN1_bn_print(out, s, rsa->e, m, off)) {
+    goto err;
+  }
+
+  if (include_private) {
+    if (!ASN1_bn_print(out, "privateExponent:", rsa->d, m, off) ||
+        !ASN1_bn_print(out, "prime1:", rsa->p, m, off) ||
+        !ASN1_bn_print(out, "prime2:", rsa->q, m, off) ||
+        !ASN1_bn_print(out, "exponent1:", rsa->dmp1, m, off) ||
+        !ASN1_bn_print(out, "exponent2:", rsa->dmq1, m, off) ||
+        !ASN1_bn_print(out, "coefficient:", rsa->iqmp, m, off)) {
+      goto err;
+    }
+  }
+  ret = 1;
+
+err:
+  if (m != NULL) {
+    OPENSSL_free(m);
+  }
+  return ret;
+}
+
+static int rsa_pub_print(BIO *bp, const EVP_PKEY *pkey, int indent,
+                         ASN1_PCTX *ctx) {
+  return do_rsa_print(bp, pkey->pkey.rsa, indent, 0);
+}
+
+
+static int rsa_priv_print(BIO *bp, const EVP_PKEY *pkey, int indent,
+                          ASN1_PCTX *ctx) {
+  return do_rsa_print(bp, pkey->pkey.rsa, indent, 1);
+}
+
+/* Given an MGF1 Algorithm ID decode to an Algorithm Identifier */
+static X509_ALGOR *rsa_mgf1_decode(X509_ALGOR *alg) {
+  const uint8_t *p;
+  int plen;
+
+  if (alg == NULL ||
+      OBJ_obj2nid(alg->algorithm) != NID_mgf1 ||
+      alg->parameter->type != V_ASN1_SEQUENCE) {
+    return NULL;
+  }
+
+  p = alg->parameter->value.sequence->data;
+  plen = alg->parameter->value.sequence->length;
+  return d2i_X509_ALGOR(NULL, &p, plen);
+}
+
+static RSA_PSS_PARAMS *rsa_pss_decode(const X509_ALGOR *alg,
+                                      X509_ALGOR **pmaskHash) {
+  const uint8_t *p;
+  int plen;
+  RSA_PSS_PARAMS *pss;
+
+  *pmaskHash = NULL;
+
+  if (!alg->parameter || alg->parameter->type != V_ASN1_SEQUENCE) {
+    return NULL;
+  }
+  p = alg->parameter->value.sequence->data;
+  plen = alg->parameter->value.sequence->length;
+  pss = d2i_RSA_PSS_PARAMS(NULL, &p, plen);
+
+  if (!pss) {
+    return NULL;
+  }
+
+  *pmaskHash = rsa_mgf1_decode(pss->maskGenAlgorithm);
+
+  return pss;
+}
+
+static int rsa_pss_param_print(BIO *bp, RSA_PSS_PARAMS *pss,
+                               X509_ALGOR *maskHash, int indent) {
+  int rv = 0;
+
+  if (!pss) {
+    if (BIO_puts(bp, " (INVALID PSS PARAMETERS)\n") <= 0) {
+      return 0;
+    }
+    return 1;
+  }
+
+  if (BIO_puts(bp, "\n") <= 0 ||
+      !BIO_indent(bp, indent, 128) ||
+      BIO_puts(bp, "Hash Algorithm: ") <= 0) {
+    goto err;
+  }
+
+  if (pss->hashAlgorithm) {
+    if (i2a_ASN1_OBJECT(bp, pss->hashAlgorithm->algorithm) <= 0) {
+      goto err;
+    }
+  } else if (BIO_puts(bp, "sha1 (default)") <= 0) {
+    goto err;
+  }
+
+  if (BIO_puts(bp, "\n") <= 0 ||
+      !BIO_indent(bp, indent, 128) ||
+      BIO_puts(bp, "Mask Algorithm: ") <= 0) {
+    goto err;
+  }
+
+  if (pss->maskGenAlgorithm) {
+    if (i2a_ASN1_OBJECT(bp, pss->maskGenAlgorithm->algorithm) <= 0 ||
+        BIO_puts(bp, " with ") <= 0) {
+      goto err;
+    }
+
+    if (maskHash) {
+      if (i2a_ASN1_OBJECT(bp, maskHash->algorithm) <= 0) {
+        goto err;
+      }
+    } else if (BIO_puts(bp, "INVALID") <= 0) {
+      goto err;
+    }
+  } else if (BIO_puts(bp, "mgf1 with sha1 (default)") <= 0) {
+    goto err;
+  }
+  BIO_puts(bp, "\n");
+
+  if (!BIO_indent(bp, indent, 128) ||
+      BIO_puts(bp, "Salt Length: 0x") <= 0) {
+    goto err;
+  }
+
+  if (pss->saltLength) {
+    if (i2a_ASN1_INTEGER(bp, pss->saltLength) <= 0) {
+      goto err;
+    }
+  } else if (BIO_puts(bp, "0x14 (default)") <= 0) {
+    goto err;
+  }
+  BIO_puts(bp, "\n");
+
+  if (!BIO_indent(bp, indent, 128) ||
+      BIO_puts(bp, "Trailer Field: 0x") <= 0) {
+    goto err;
+  }
+
+  if (pss->trailerField) {
+    if (i2a_ASN1_INTEGER(bp, pss->trailerField) <= 0) {
+      goto err;
+    }
+  } else if (BIO_puts(bp, "BC (default)") <= 0) {
+    goto err;
+  }
+  BIO_puts(bp, "\n");
+
+  rv = 1;
+
+err:
+  return rv;
+}
+
+static int rsa_sig_print(BIO *bp, const X509_ALGOR *sigalg,
+                         const ASN1_STRING *sig, int indent, ASN1_PCTX *pctx) {
+  if (OBJ_obj2nid(sigalg->algorithm) == NID_rsassaPss) {
+    int rv;
+    RSA_PSS_PARAMS *pss;
+    X509_ALGOR *maskHash;
+
+    pss = rsa_pss_decode(sigalg, &maskHash);
+    rv = rsa_pss_param_print(bp, pss, maskHash, indent);
+    if (pss) {
+      RSA_PSS_PARAMS_free(pss);
+    }
+    if (maskHash) {
+      X509_ALGOR_free(maskHash);
+    }
+    if (!rv) {
+      return 0;
+    }
+  } else if (!sig && BIO_puts(bp, "\n") <= 0) {
+    return 0;
+  }
+
+  if (sig) {
+    return X509_signature_dump(bp, sig, indent);
+  }
+  return 1;
+}
+
+static int rsa_pkey_ctrl(EVP_PKEY *pkey, int op, long arg1, void *arg2) {
+  X509_ALGOR *alg = NULL;
+  switch (op) {
+    case ASN1_PKEY_CTRL_DEFAULT_MD_NID:
+      *(int *)arg2 = NID_sha1;
+      return 1;
+
+    default:
+      return -2;
+  }
+
+  if (alg) {
+    X509_ALGOR_set0(alg, OBJ_nid2obj(NID_rsaEncryption), V_ASN1_NULL, 0);
+  }
+
+  return 1;
+}
+
+static int old_rsa_priv_decode(EVP_PKEY *pkey, const unsigned char **pder,
+                               int derlen) {
+  RSA *rsa = d2i_RSAPrivateKey(NULL, pder, derlen);
+  if (rsa == NULL) {
+    OPENSSL_PUT_ERROR(EVP, old_rsa_priv_decode, ERR_R_RSA_LIB);
+    return 0;
+  }
+  EVP_PKEY_assign_RSA(pkey, rsa);
+  return 1;
+}
+
+static int old_rsa_priv_encode(const EVP_PKEY *pkey, unsigned char **pder) {
+  return i2d_RSAPrivateKey(pkey->pkey.rsa, pder);
+}
+
+/* allocate and set algorithm ID from EVP_MD, default SHA1 */
+static int rsa_md_to_algor(X509_ALGOR **palg, const EVP_MD *md) {
+  if (EVP_MD_type(md) == NID_sha1) {
+    return 1;
+  }
+  *palg = X509_ALGOR_new();
+  if (!*palg) {
+    return 0;
+  }
+  X509_ALGOR_set_md(*palg, md);
+  return 1;
+}
+
+/* Allocate and set MGF1 algorithm ID from EVP_MD */
+static int rsa_md_to_mgf1(X509_ALGOR **palg, const EVP_MD *mgf1md) {
+  X509_ALGOR *algtmp = NULL;
+  ASN1_STRING *stmp = NULL;
+  *palg = NULL;
+
+  if (EVP_MD_type(mgf1md) == NID_sha1) {
+    return 1;
+  }
+  /* need to embed algorithm ID inside another */
+  if (!rsa_md_to_algor(&algtmp, mgf1md) ||
+      !ASN1_item_pack(algtmp, ASN1_ITEM_rptr(X509_ALGOR), &stmp)) {
+    goto err;
+  }
+  *palg = X509_ALGOR_new();
+  if (!*palg) {
+    goto err;
+  }
+  X509_ALGOR_set0(*palg, OBJ_nid2obj(NID_mgf1), V_ASN1_SEQUENCE, stmp);
+  stmp = NULL;
+
+err:
+  if (stmp)
+    ASN1_STRING_free(stmp);
+  if (algtmp)
+    X509_ALGOR_free(algtmp);
+  if (*palg)
+    return 1;
+
+  return 0;
+}
+
+/* convert algorithm ID to EVP_MD, default SHA1 */
+static const EVP_MD *rsa_algor_to_md(X509_ALGOR *alg) {
+  const EVP_MD *md;
+  if (!alg) {
+    return EVP_sha1();
+  }
+  md = EVP_get_digestbyobj(alg->algorithm);
+  if (md == NULL) {
+    OPENSSL_PUT_ERROR(EVP, rsa_algor_to_md, EVP_R_UNKNOWN_DIGEST);
+  }
+  return md;
+}
+
+/* convert MGF1 algorithm ID to EVP_MD, default SHA1 */
+static const EVP_MD *rsa_mgf1_to_md(X509_ALGOR *alg, X509_ALGOR *maskHash) {
+  const EVP_MD *md;
+  if (!alg) {
+    return EVP_sha1();
+  }
+  /* Check mask and lookup mask hash algorithm */
+  if (OBJ_obj2nid(alg->algorithm) != NID_mgf1) {
+    OPENSSL_PUT_ERROR(EVP, rsa_mgf1_to_md, EVP_R_UNSUPPORTED_MASK_ALGORITHM);
+    return NULL;
+  }
+  if (!maskHash) {
+    OPENSSL_PUT_ERROR(EVP, rsa_mgf1_to_md, EVP_R_UNSUPPORTED_MASK_PARAMETER);
+    return NULL;
+  }
+  md = EVP_get_digestbyobj(maskHash->algorithm);
+  if (md == NULL) {
+    OPENSSL_PUT_ERROR(EVP, rsa_mgf1_to_md, EVP_R_UNKNOWN_MASK_DIGEST);
+    return NULL;
+  }
+  return md;
+}
+
+/* rsa_ctx_to_pss converts EVP_PKEY_CTX in PSS mode into corresponding
+ * algorithm parameter, suitable for setting as an AlgorithmIdentifier. */
+static ASN1_STRING *rsa_ctx_to_pss(EVP_PKEY_CTX *pkctx) {
+  const EVP_MD *sigmd, *mgf1md;
+  RSA_PSS_PARAMS *pss = NULL;
+  ASN1_STRING *os = NULL;
+  EVP_PKEY *pk = EVP_PKEY_CTX_get0_pkey(pkctx);
+  int saltlen, rv = 0;
+
+  if (EVP_PKEY_CTX_get_signature_md(pkctx, &sigmd) <= 0 ||
+      EVP_PKEY_CTX_get_rsa_mgf1_md(pkctx, &mgf1md) <= 0 ||
+      !EVP_PKEY_CTX_get_rsa_pss_saltlen(pkctx, &saltlen)) {
+    goto err;
+  }
+
+  if (saltlen == -1) {
+    saltlen = EVP_MD_size(sigmd);
+  } else if (saltlen == -2) {
+    saltlen = EVP_PKEY_size(pk) - EVP_MD_size(sigmd) - 2;
+    if (((EVP_PKEY_bits(pk) - 1) & 0x7) == 0) {
+      saltlen--;
+    }
+  } else {
+    goto err;
+  }
+
+  pss = RSA_PSS_PARAMS_new();
+  if (!pss) {
+    goto err;
+  }
+
+  if (saltlen != 20) {
+    pss->saltLength = ASN1_INTEGER_new();
+    if (!pss->saltLength ||
+        !ASN1_INTEGER_set(pss->saltLength, saltlen)) {
+      goto err;
+    }
+  }
+
+  if (!rsa_md_to_algor(&pss->hashAlgorithm, sigmd) ||
+      !rsa_md_to_mgf1(&pss->maskGenAlgorithm, mgf1md)) {
+    goto err;
+  }
+
+  /* Finally create string with pss parameter encoding. */
+  if (!ASN1_item_pack(pss, ASN1_ITEM_rptr(RSA_PSS_PARAMS), &os)) {
+    goto err;
+  }
+  rv = 1;
+
+err:
+  if (pss)
+    RSA_PSS_PARAMS_free(pss);
+  if (rv)
+    return os;
+  if (os)
+    ASN1_STRING_free(os);
+  return NULL;
+}
+
+/* From PSS AlgorithmIdentifier set public key parameters. If pkey
+ * isn't NULL then the EVP_MD_CTX is setup and initalised. If it
+ * is NULL parameters are passed to pkctx instead. */
+static int rsa_pss_to_ctx(EVP_MD_CTX *ctx, EVP_PKEY_CTX *pkctx,
+                          X509_ALGOR *sigalg, EVP_PKEY *pkey) {
+  int ret = -1;
+  int saltlen;
+  const EVP_MD *mgf1md = NULL, *md = NULL;
+  RSA_PSS_PARAMS *pss;
+  X509_ALGOR *maskHash;
+
+  /* Sanity check: make sure it is PSS */
+  if (OBJ_obj2nid(sigalg->algorithm) != NID_rsassaPss) {
+    OPENSSL_PUT_ERROR(EVP, rsa_pss_to_ctx, EVP_R_UNSUPPORTED_SIGNATURE_TYPE);
+    return -1;
+  }
+  /* Decode PSS parameters */
+  pss = rsa_pss_decode(sigalg, &maskHash);
+  if (pss == NULL) {
+    OPENSSL_PUT_ERROR(EVP, rsa_pss_to_ctx, EVP_R_INVALID_PSS_PARAMETERS);
+    goto err;
+  }
+
+  mgf1md = rsa_mgf1_to_md(pss->maskGenAlgorithm, maskHash);
+  if (!mgf1md) {
+    goto err;
+  }
+  md = rsa_algor_to_md(pss->hashAlgorithm);
+  if (!md) {
+    goto err;
+  }
+
+  saltlen = 20;
+  if (pss->saltLength) {
+    saltlen = ASN1_INTEGER_get(pss->saltLength);
+
+    /* Could perform more salt length sanity checks but the main
+     * RSA routines will trap other invalid values anyway. */
+    if (saltlen < 0) {
+      OPENSSL_PUT_ERROR(EVP, rsa_pss_to_ctx, EVP_R_INVALID_SALT_LENGTH);
+      goto err;
+    }
+  }
+
+  /* low-level routines support only trailer field 0xbc (value 1)
+   * and PKCS#1 says we should reject any other value anyway. */
+  if (pss->trailerField && ASN1_INTEGER_get(pss->trailerField) != 1) {
+    OPENSSL_PUT_ERROR(EVP, rsa_pss_to_ctx, EVP_R_INVALID_TRAILER);
+    goto err;
+  }
+
+  if (pkey) {
+    if (!EVP_DigestVerifyInit(ctx, &pkctx, md, NULL, pkey)) {
+      goto err;
+    }
+  } else {
+    const EVP_MD *checkmd;
+    if (EVP_PKEY_CTX_get_signature_md(pkctx, &checkmd) <= 0) {
+      goto err;
+    }
+    if (EVP_MD_type(md) != EVP_MD_type(checkmd)) {
+      OPENSSL_PUT_ERROR(EVP, rsa_pss_to_ctx, EVP_R_DIGEST_DOES_NOT_MATCH);
+      goto err;
+    }
+  }
+
+  if (EVP_PKEY_CTX_set_rsa_padding(pkctx, RSA_PKCS1_PSS_PADDING) <= 0 ||
+      EVP_PKEY_CTX_set_rsa_pss_saltlen(pkctx, saltlen) <= 0 ||
+      EVP_PKEY_CTX_set_rsa_mgf1_md(pkctx, mgf1md) <= 0) {
+    goto err;
+  }
+
+  ret = 1;
+
+err:
+  RSA_PSS_PARAMS_free(pss);
+  if (maskHash) {
+    X509_ALGOR_free(maskHash);
+  }
+  return ret;
+}
+
+/* Customised RSA item verification routine. This is called
+ * when a signature is encountered requiring special handling. We
+ * currently only handle PSS. */
+static int rsa_item_verify(EVP_MD_CTX *ctx, const ASN1_ITEM *it, void *asn,
+                           X509_ALGOR *sigalg, ASN1_BIT_STRING *sig,
+                           EVP_PKEY *pkey) {
+  /* Sanity check: make sure it is PSS */
+  if (OBJ_obj2nid(sigalg->algorithm) != NID_rsassaPss) {
+    OPENSSL_PUT_ERROR(EVP, rsa_item_verify, EVP_R_UNSUPPORTED_SIGNATURE_TYPE);
+    return -1;
+  }
+  if (rsa_pss_to_ctx(ctx, NULL, sigalg, pkey)) {
+    /* Carry on */
+    return 2;
+  }
+
+  return -1;
+}
+
+static int rsa_item_sign(EVP_MD_CTX *ctx, const ASN1_ITEM *it, void *asn,
+                         X509_ALGOR *alg1, X509_ALGOR *alg2,
+                         ASN1_BIT_STRING *sig) {
+  int pad_mode;
+  EVP_PKEY_CTX *pkctx = ctx->pctx;
+  if (EVP_PKEY_CTX_get_rsa_padding(pkctx, &pad_mode) <= 0) {
+    return 0;
+  }
+  if (pad_mode == RSA_PKCS1_PADDING) {
+    return 2;
+  }
+  if (pad_mode == RSA_PKCS1_PSS_PADDING) {
+    ASN1_STRING *os1 = rsa_ctx_to_pss(pkctx);
+    if (!os1) {
+      return 0;
+    }
+    /* Duplicate parameters if we have to */
+    if (alg2) {
+      ASN1_STRING *os2 = ASN1_STRING_dup(os1);
+      if (!os2) {
+        ASN1_STRING_free(os1);
+        return 0;
+      }
+      X509_ALGOR_set0(alg2, OBJ_nid2obj(NID_rsassaPss), V_ASN1_SEQUENCE, os2);
+    }
+    X509_ALGOR_set0(alg1, OBJ_nid2obj(NID_rsassaPss), V_ASN1_SEQUENCE, os1);
+    return 3;
+  }
+  return 2;
+}
+
+const EVP_PKEY_ASN1_METHOD rsa_asn1_meth = {
+  EVP_PKEY_RSA,
+  EVP_PKEY_RSA,
+  ASN1_PKEY_SIGPARAM_NULL,
+
+  "RSA",
+  "OpenSSL RSA method",
+
+  rsa_pub_decode,
+  rsa_pub_encode,
+  rsa_pub_cmp,
+  rsa_pub_print,
+
+  rsa_priv_decode,
+  rsa_priv_encode,
+  rsa_priv_print,
+
+  int_rsa_size,
+  rsa_bits,
+
+  0,0,0,0,0,0,
+
+  rsa_sig_print,
+  int_rsa_free,
+  rsa_pkey_ctrl,
+
+  old_rsa_priv_decode,
+  old_rsa_priv_encode,
+
+  rsa_item_verify,
+  rsa_item_sign,
+};
+
+const EVP_PKEY_ASN1_METHOD rsa_asn1_meth_2 = {
+  EVP_PKEY_RSA2,
+  EVP_PKEY_RSA,
+  ASN1_PKEY_ALIAS,
+};
diff --git a/crypto/evp/pbkdf.c b/crypto/evp/pbkdf.c
new file mode 100644
index 0000000..4ab10f4
--- /dev/null
+++ b/crypto/evp/pbkdf.c
@@ -0,0 +1,140 @@
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project 1999.
+ */
+/* ====================================================================
+ * Copyright (c) 1999 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    licensing@OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com). */
+
+#include <openssl/evp.h>
+
+#include <openssl/hmac.h>
+
+
+int PKCS5_PBKDF2_HMAC(const char *password, int password_len,
+                      const uint8_t *salt, size_t salt_len, unsigned iterations,
+                      const EVP_MD *digest, size_t key_len, uint8_t *out_key) {
+  uint8_t digest_tmp[EVP_MAX_MD_SIZE], *p, itmp[4];
+  size_t cplen, mdlen, tkeylen, k;
+  unsigned j;
+  uint32_t i = 1;
+  HMAC_CTX hctx_tpl, hctx;
+
+  mdlen = EVP_MD_size(digest);
+  HMAC_CTX_init(&hctx_tpl);
+  p = out_key;
+  tkeylen = key_len;
+  if (password == NULL) {
+    password_len = 0;
+  } else if (password_len == -1) {
+    /* TODO(fork): remove this hack. The OpenSSL code took the strlen when the
+     * length is given as -1. */
+    password_len = strlen(password);
+  }
+  if (!HMAC_Init_ex(&hctx_tpl, password, password_len, digest, NULL)) {
+    HMAC_CTX_cleanup(&hctx_tpl);
+    return 0;
+  }
+  while (tkeylen) {
+    if (tkeylen > mdlen) {
+      cplen = mdlen;
+    } else {
+      cplen = tkeylen;
+    }
+    /* We are unlikely to ever use more than 256 blocks (5120 bits!)
+     * but just in case... */
+    itmp[0] = (uint8_t)((i >> 24) & 0xff);
+    itmp[1] = (uint8_t)((i >> 16) & 0xff);
+    itmp[2] = (uint8_t)((i >> 8) & 0xff);
+    itmp[3] = (uint8_t)(i & 0xff);
+    if (!HMAC_CTX_copy(&hctx, &hctx_tpl)) {
+      HMAC_CTX_cleanup(&hctx_tpl);
+      return 0;
+    }
+    if (!HMAC_Update(&hctx, salt, salt_len) ||
+        !HMAC_Update(&hctx, itmp, 4) ||
+        !HMAC_Final(&hctx, digest_tmp, NULL)) {
+      HMAC_CTX_cleanup(&hctx_tpl);
+      HMAC_CTX_cleanup(&hctx);
+      return 0;
+    }
+    HMAC_CTX_cleanup(&hctx);
+    memcpy(p, digest_tmp, cplen);
+    for (j = 1; j < iterations; j++) {
+      if (!HMAC_CTX_copy(&hctx, &hctx_tpl)) {
+        HMAC_CTX_cleanup(&hctx_tpl);
+        return 0;
+      }
+      if (!HMAC_Update(&hctx, digest_tmp, mdlen) ||
+          !HMAC_Final(&hctx, digest_tmp, NULL)) {
+        HMAC_CTX_cleanup(&hctx_tpl);
+        HMAC_CTX_cleanup(&hctx);
+        return 0;
+      }
+      HMAC_CTX_cleanup(&hctx);
+      for (k = 0; k < cplen; k++) {
+        p[k] ^= digest_tmp[k];
+      }
+    }
+    tkeylen -= cplen;
+    i++;
+    p += cplen;
+  }
+  HMAC_CTX_cleanup(&hctx_tpl);
+  return 1;
+}
+
+int PKCS5_PBKDF2_HMAC_SHA1(const char *password, int password_len,
+                           const uint8_t *salt, size_t salt_len,
+                           unsigned iterations, size_t key_len,
+                           uint8_t *out_key) {
+  return PKCS5_PBKDF2_HMAC(password, password_len, salt, salt_len, iterations,
+                           EVP_sha1(), key_len, out_key);
+}
diff --git a/crypto/evp/sign.c b/crypto/evp/sign.c
new file mode 100644
index 0000000..c32e5ce
--- /dev/null
+++ b/crypto/evp/sign.c
@@ -0,0 +1,162 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.] */
+
+#include <openssl/evp.h>
+
+#include <openssl/digest.h>
+#include <openssl/err.h>
+
+#include "internal.h"
+
+
+int EVP_SignInit_ex(EVP_MD_CTX *ctx, const EVP_MD *type, ENGINE *impl) {
+  return EVP_DigestInit_ex(ctx, type, impl);
+}
+
+int EVP_SignInit(EVP_MD_CTX *ctx, const EVP_MD *type) {
+  return EVP_DigestInit(ctx, type);
+}
+
+int EVP_SignUpdate(EVP_MD_CTX *ctx, const void *data, size_t len) {
+  return EVP_DigestUpdate(ctx, data, len);
+}
+
+int EVP_SignFinal(const EVP_MD_CTX *ctx, uint8_t *sig,
+                  unsigned int *out_sig_len, EVP_PKEY *pkey) {
+  uint8_t m[EVP_MAX_MD_SIZE];
+  unsigned int m_len;
+  int ret = 0;
+  EVP_MD_CTX tmp_ctx;
+  EVP_PKEY_CTX *pkctx = NULL;
+  size_t sig_len = EVP_PKEY_size(pkey);
+
+  *out_sig_len = 0;
+  EVP_MD_CTX_init(&tmp_ctx);
+  if (!EVP_MD_CTX_copy_ex(&tmp_ctx, ctx) ||
+      !EVP_DigestFinal_ex(&tmp_ctx, m, &m_len)) {
+    goto out;
+  }
+  EVP_MD_CTX_cleanup(&tmp_ctx);
+
+/* TODO(fork): this used to be used only with SHA-family hashes. Now we've
+ * removed the flag completely. Why was it added for just those hashes? */
+#if 0
+    if (ctx->digest->flags & EVP_MD_FLAG_PKEY_METHOD_SIGNATURE) {
+#endif
+
+  pkctx = EVP_PKEY_CTX_new(pkey, NULL);
+  if (!pkctx || EVP_PKEY_sign_init(pkctx) <= 0 ||
+      EVP_PKEY_CTX_set_signature_md(pkctx, ctx->digest) <= 0 ||
+      EVP_PKEY_sign(pkctx, sig, &sig_len, m, m_len) <= 0) {
+    goto out;
+  }
+  *out_sig_len = sig_len;
+  ret = 1;
+
+out:
+  if (pkctx) {
+    EVP_PKEY_CTX_free(pkctx);
+  }
+
+  return ret;
+}
+
+int EVP_VerifyInit_ex(EVP_MD_CTX *ctx, const EVP_MD *type, ENGINE *impl) {
+  return EVP_DigestInit_ex(ctx, type, impl);
+}
+
+int EVP_VerifyInit(EVP_MD_CTX *ctx, const EVP_MD *type) {
+  return EVP_DigestInit(ctx, type);
+}
+
+int EVP_VerifyUpdate(EVP_MD_CTX *ctx, const void *data, size_t len) {
+  return EVP_DigestUpdate(ctx, data, len);
+}
+
+int EVP_VerifyFinal(EVP_MD_CTX *ctx, const uint8_t *sig, size_t sig_len,
+                    EVP_PKEY *pkey) {
+  uint8_t m[EVP_MAX_MD_SIZE];
+  unsigned int m_len;
+  int ret = 0;
+  EVP_MD_CTX tmp_ctx;
+  EVP_PKEY_CTX *pkctx = NULL;
+
+  EVP_MD_CTX_init(&tmp_ctx);
+  if (!EVP_MD_CTX_copy_ex(&tmp_ctx, ctx) ||
+      !EVP_DigestFinal_ex(&tmp_ctx, m, &m_len)) {
+    EVP_MD_CTX_cleanup(&tmp_ctx);
+    goto out;
+  }
+  EVP_MD_CTX_cleanup(&tmp_ctx);
+
+/* TODO(fork): this used to be used only with SHA-family hashes. Now we've
+ * removed the flag completely. Why was it added for just those hashes? */
+#if 0
+    if (ctx->digest->flags & EVP_MD_FLAG_PKEY_METHOD_SIGNATURE) {
+#endif
+  pkctx = EVP_PKEY_CTX_new(pkey, NULL);
+  if (!pkctx ||
+      EVP_PKEY_verify_init(pkctx) <= 0 ||
+      EVP_PKEY_CTX_set_signature_md(pkctx, ctx->digest) <= 0) {
+    goto out;
+  }
+  ret = EVP_PKEY_verify(pkctx, sig, sig_len, m, m_len);
+
+out:
+  EVP_PKEY_CTX_free(pkctx);
+  return ret;
+}
+