diff options
author | Adam Langley <agl@chromium.org> | 2014-06-20 23:00:00 +0400 |
---|---|---|
committer | Adam Langley <agl@chromium.org> | 2014-06-21 00:17:32 +0400 |
commit | 95c29f3cd1f6c08c6c0927868683392eea727ccb (patch) | |
tree | 012767320ced9abca61472a4daa4c4a56b7ebe2b /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.txt | 30 | ||||
-rw-r--r-- | crypto/evp/asn1.c | 170 | ||||
-rw-r--r-- | crypto/evp/digestsign.c | 212 | ||||
-rw-r--r-- | crypto/evp/evp.c | 425 | ||||
-rw-r--r-- | crypto/evp/evp.h | 819 | ||||
-rw-r--r-- | crypto/evp/evp_ctx.c | 548 | ||||
-rw-r--r-- | crypto/evp/evp_error.c | 119 | ||||
-rw-r--r-- | crypto/evp/example_sign.c | 198 | ||||
-rw-r--r-- | crypto/evp/internal.h | 233 | ||||
-rw-r--r-- | crypto/evp/p_ec.c | 423 | ||||
-rw-r--r-- | crypto/evp/p_ec_asn1.c | 577 | ||||
-rw-r--r-- | crypto/evp/p_hmac.c | 215 | ||||
-rw-r--r-- | crypto/evp/p_hmac_asn1.c | 99 | ||||
-rw-r--r-- | crypto/evp/p_rsa.c | 596 | ||||
-rw-r--r-- | crypto/evp/p_rsa_asn1.c | 751 | ||||
-rw-r--r-- | crypto/evp/pbkdf.c | 140 | ||||
-rw-r--r-- | crypto/evp/sign.c | 162 |
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; +} + |