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;
}