crypto/fipsmodule/evp/p_ed25519ph.c (144 lines of code) (raw):

/* Copyright (c) 2017, Google Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include <openssl/evp.h> #include <openssl/curve25519.h> #include <openssl/err.h> #include <openssl/mem.h> #include "../../internal.h" #include "internal.h" typedef struct { uint8_t context[255]; size_t context_len; } ED25519PH_PKEY_CTX; static int pkey_ed25519ph_init(EVP_PKEY_CTX *ctx) { ED25519PH_PKEY_CTX *dctx = OPENSSL_zalloc(sizeof(ED25519PH_PKEY_CTX)); if (dctx == NULL) { return 0; } ctx->data = dctx; return 1; } static void pkey_ed25519ph_cleanup(EVP_PKEY_CTX *ctx) { ED25519PH_PKEY_CTX *dctx = ctx->data; if (!dctx) { return; } OPENSSL_free(dctx); } static int pkey_ed25519ph_copy(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src) { if (!pkey_ed25519ph_init(dst)) { return 0; } ED25519PH_PKEY_CTX *dctx = dst->data; ED25519PH_PKEY_CTX *sctx = src->data; GUARD_PTR(dctx); GUARD_PTR(sctx); OPENSSL_memcpy(dctx->context, sctx->context, sizeof(sctx->context)); dctx->context_len = sctx->context_len; return 1; } static int pkey_ed25519ph_sign(EVP_PKEY_CTX *ctx, uint8_t *sig, size_t *siglen, const uint8_t *tbs, size_t tbslen) { ED25519_KEY *key = ctx->pkey->pkey.ptr; if (!key->has_private) { OPENSSL_PUT_ERROR(EVP, EVP_R_NOT_A_PRIVATE_KEY); return 0; } if (sig == NULL) { *siglen = ED25519_SIGNATURE_LEN; return 1; } if (*siglen < ED25519_SIGNATURE_LEN) { OPENSSL_PUT_ERROR(EVP, EVP_R_BUFFER_TOO_SMALL); return 0; } if (tbslen < SHA512_DIGEST_LENGTH) { OPENSSL_PUT_ERROR(EVP, EVP_R_BUFFER_TOO_SMALL); return 0; } ED25519PH_PKEY_CTX *dctx = ctx->data; GUARD_PTR(dctx); if (!ED25519ph_sign_digest(sig, tbs, key->key, dctx->context, dctx->context_len)) { return 0; } *siglen = ED25519_SIGNATURE_LEN; return 1; } static int pkey_ed25519ph_verify(EVP_PKEY_CTX *ctx, const uint8_t *sig, size_t siglen, const uint8_t *tbs, size_t tbslen) { ED25519_KEY *key = ctx->pkey->pkey.ptr; ED25519PH_PKEY_CTX *dctx = ctx->data; GUARD_PTR(dctx); if (siglen != ED25519_SIGNATURE_LEN || tbslen < SHA512_DIGEST_LENGTH || !ED25519ph_verify_digest(tbs, sig, key->key + ED25519_PUBLIC_KEY_OFFSET, dctx->context, dctx->context_len)) { OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_SIGNATURE); return 0; } return 1; } static int pkey_ed25519ph_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2) { GUARD_PTR(ctx); ED25519PH_PKEY_CTX *dctx = (ED25519PH_PKEY_CTX *)ctx->data; switch (type) { case EVP_PKEY_CTRL_MD: { const EVP_MD *md = p2; int md_type = EVP_MD_type(md); // MUST be SHA-512 if (md_type != NID_sha512) { OPENSSL_PUT_ERROR(EVP, EVP_R_COMMAND_NOT_SUPPORTED); return 0; } break; } case EVP_PKEY_CTRL_SIGNING_CONTEXT: { EVP_PKEY_CTX_SIGNATURE_CONTEXT_PARAMS *params = p2; if (!params || !dctx || params->context_len > sizeof(dctx->context)) { return 0; } OPENSSL_memcpy(dctx->context, params->context, params->context_len); dctx->context_len = params->context_len; break; } case EVP_PKEY_CTRL_GET_SIGNING_CONTEXT: { EVP_PKEY_CTX_SIGNATURE_CONTEXT_PARAMS *params = p2; if (!params || !dctx) { return 0; } if (dctx->context_len == 0) { params->context = NULL; params->context_len = 0; } else { params->context = dctx->context; params->context_len = dctx->context_len; } return 1; } default: OPENSSL_PUT_ERROR(EVP, EVP_R_COMMAND_NOT_SUPPORTED); return 0; } return 1; } DEFINE_METHOD_FUNCTION(EVP_PKEY_METHOD, EVP_PKEY_ed25519ph_pkey_meth) { out->pkey_id = EVP_PKEY_ED25519PH; out->init = pkey_ed25519ph_init; out->copy = pkey_ed25519ph_copy; out->cleanup = pkey_ed25519ph_cleanup; out->keygen = NULL; out->sign_init = NULL; out->sign = pkey_ed25519ph_sign; out->verify_init = NULL; out->verify = pkey_ed25519ph_verify; out->verify_message = NULL; out->verify_recover = NULL; out->encrypt = NULL; out->decrypt = NULL; out->derive = NULL; out->paramgen = NULL; out->ctrl = pkey_ed25519ph_ctrl; out->ctrl_str = NULL; out->keygen_deterministic = NULL; out->encapsulate_deterministic = NULL; out->encapsulate = NULL; out->decapsulate = NULL; }