Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/boringssl.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdam Langley <agl@chromium.org>2014-06-20 23:00:00 +0400
committerAdam Langley <agl@chromium.org>2014-06-21 00:17:32 +0400
commit95c29f3cd1f6c08c6c0927868683392eea727ccb (patch)
tree012767320ced9abca61472a4daa4c4a56b7ebe2b /crypto/evp
Inital import.
Initial fork from f2d678e6e89b6508147086610e985d4e8416e867 (1.0.2 beta). (This change contains substantial changes from the original and effectively starts a new history.)
Diffstat (limited to 'crypto/evp')
-rw-r--r--crypto/evp/CMakeLists.txt30
-rw-r--r--crypto/evp/asn1.c170
-rw-r--r--crypto/evp/digestsign.c212
-rw-r--r--crypto/evp/evp.c425
-rw-r--r--crypto/evp/evp.h819
-rw-r--r--crypto/evp/evp_ctx.c548
-rw-r--r--crypto/evp/evp_error.c119
-rw-r--r--crypto/evp/example_sign.c198
-rw-r--r--crypto/evp/internal.h233
-rw-r--r--crypto/evp/p_ec.c423
-rw-r--r--crypto/evp/p_ec_asn1.c577
-rw-r--r--crypto/evp/p_hmac.c215
-rw-r--r--crypto/evp/p_hmac_asn1.c99
-rw-r--r--crypto/evp/p_rsa.c596
-rw-r--r--crypto/evp/p_rsa_asn1.c751
-rw-r--r--crypto/evp/pbkdf.c140
-rw-r--r--crypto/evp/sign.c162
17 files changed, 5717 insertions, 0 deletions
diff --git a/crypto/evp/CMakeLists.txt b/crypto/evp/CMakeLists.txt
new file mode 100644
index 00000000..c3d8d8a3
--- /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 00000000..50bdb064
--- /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 00000000..08968ed2
--- /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 00000000..1d6fd8c9
--- /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 00000000..ce40aa5c
--- /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 00000000..5c3755aa
--- /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 00000000..0b4d2f2d
--- /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 00000000..4bbe1942
--- /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 00000000..76f206e7
--- /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 00000000..2305e6e8
--- /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 00000000..d4eec13c
--- /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 00000000..b55db7a2
--- /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 00000000..cabd7379
--- /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 00000000..2fab371f
--- /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 00000000..6b94ed7d
--- /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 00000000..4ab10f45
--- /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 00000000..c32e5ce6
--- /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;
+}
+