ecdsa.c   [plain text]


/*
 * Copyright (c) 2006 - 2008 Kungliga Tekniska Högskolan
 * (Royal Institute of Technology, Stockholm, Sweden).
 * 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. Neither the name of the Institute nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE 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.
 */

#include <config.h>

#include <stdio.h>
#include <stdlib.h>
#include <krb5-types.h>
#include <rfc2459_asn1.h>
#include <ecdsa.h>
#include "common.h"
#include <roken.h>

ECDSA *
ECDSA_new(void)
{
    return ECDSA_new_method(NULL);
}

/**
 * Allocate a new ECDSA object using the engine, if NULL is specified as
 * the engine, use the default ECDSA engine as returned by
 * ENGINE_get_default_ECDSA().
 *
 * @param engine Specific what ENGINE ECDSA provider should be used.
 *
 * @return a newly allocated ECDSA object. Free with ECDSA_free().
 *
 */

ECDSA *
ECDSA_new_method(ENGINE *engine)
{
    ECDSA *ecdsa;

    ecdsa = calloc(1, sizeof(*ecdsa));
    if (ecdsa == NULL)
	return NULL;

    ecdsa->references = 1;

    if (engine) {
	ENGINE_up_ref(engine);
	ecdsa->engine = engine;
    } else {
	ecdsa->engine = ENGINE_get_default_ECDSA();
    }

    if (ecdsa->engine) {
	ecdsa->meth = ENGINE_get_ECDSA(ecdsa->engine);
	if (ecdsa->meth == NULL) {
	    ENGINE_finish(engine);
	    free(ecdsa);
	    return 0;
	}
    }

    if (ecdsa->meth == NULL)
	ecdsa->meth = rk_UNCONST(ECDSA_get_default_method());

    (*ecdsa->meth->init)(ecdsa);

    return ecdsa;
}

/**
 * Free an allocation ECDSA object.
 *
 * @param ecdsa the ECDSA object to free.
 */

void
ECDSA_free(ECDSA *ecdsa)
{
    if (ecdsa->references <= 0)
	abort();

    if (--ecdsa->references > 0)
	return;

    (*ecdsa->meth->finish)(ecdsa);

    if (ecdsa->engine)
	ENGINE_finish(ecdsa->engine);

    memset(ecdsa, 0, sizeof(*ecdsa));
    free(ecdsa);
}

/**
 * Add an extra reference to the ECDSA object. The object should be free
 * with ECDSA_free() to drop the reference.
 *
 * @param ecdsa the object to add reference counting too.
 *
 * @return the current reference count, can't safely be used except
 * for debug printing.
 *
 */

int
ECDSA_up_ref(ECDSA *ecdsa)
{
    return ++ecdsa->references;
}

/**
 * Return the ECDSA_METHOD used for this ECDSA object.
 *
 * @param ecdsa the object to get the method from.
 *
 * @return the method used for this ECDSA object.
 *
 */

const ECDSA_METHOD *
ECDSA_get_method(const ECDSA *ecdsa)
{
    return ecdsa->meth;
}

/**
 * Set a new method for the ECDSA keypair.
 *
 * @param ecdsa ecdsa parameter.
 * @param method the new method for the ECDSA parameter.
 *
 * @return 1 on success.
 *
 */

int
ECDSA_set_method(ECDSA *ecdsa, const ECDSA_METHOD *method)
{
    (*ecdsa->meth->finish)(ecdsa);

    if (ecdsa->engine) {
	ENGINE_finish(ecdsa->engine);
	ecdsa->engine = NULL;
    }

    ecdsa->meth = method;
    (*ecdsa->meth->init)(ecdsa);
    return 1;
}

/**
 * Set the application data for the ECDSA object.
 *
 * @param ecdsa the ecdsa object to set the parameter for
 * @param arg the data object to store
 *
 * @return 1 on success.
 *
 */

int
ECDSA_set_app_data(ECDSA *ecdsa, void *arg)
{
    ecdsa->ex_data.sk = arg;
    return 1;
}

/**
 * Get the application data for the ECDSA object.
 *
 * @param ecdsa the ecdsa object to get the parameter for
 *
 * @return the data object
 *
 */

void *
ECDSA_get_app_data(const ECDSA *ecdsa)
{
    return ecdsa->ex_data.sk;
}

#define ECDSAFUNC(name, body) \
int \
name(int flen,const unsigned char* f, unsigned char* t, ECDSA* r, int p){\
    return body; \
}

int
ECDSA_sign(int type, const unsigned char *from, unsigned int flen,
	 unsigned char *to, unsigned int *tlen, ECDSA *ecdsa)
{
    if (ecdsa->meth->ecdsa_sign)
	return ecdsa->meth->ecdsa_sign(type, from, flen, to, tlen, ecdsa);

    return 0;
}

int
ECDSA_verify(int type, const unsigned char *from, unsigned int flen,
	   unsigned char *sigbuf, unsigned int siglen, ECDSA *ecdsa)
{
    if (ecdsa->meth->ecdsa_verify)
	return ecdsa->meth->ecdsa_verify(type, from, flen, sigbuf, siglen, ecdsa);

    return 0;
}

int
ECDSA_size(EC_KEY *ecdsa)
{
    return ECDSA_KEY_SIZE;
}


/*
 * A NULL ECDSA_METHOD that returns failure for all operations. This is
 * used as the default ECDSA method if we don't have any native
 * support.
 */

static ECDSAFUNC(null_ecdsa_public_encrypt, -1)
static ECDSAFUNC(null_ecdsa_public_decrypt, -1)
static ECDSAFUNC(null_ecdsa_private_encrypt, -1)
static ECDSAFUNC(null_ecdsa_private_decrypt, -1)


/*
 *
 */

static int
null_ecdsa_init(ECDSA *ecdsa)
{
    return 1;
}

static int
null_ecdsa_finish(ECDSA *ecdsa)
{
    return 1;
}

static const ECDSA_METHOD ecdsa_null_method = {
    "hcrypto null ECDSA",
    null_ecdsa_public_encrypt,
    null_ecdsa_public_decrypt,
    null_ecdsa_private_encrypt,
    null_ecdsa_private_decrypt,
    null_ecdsa_init,
    null_ecdsa_finish,
    0,
    NULL,
    NULL
};

const ECDSA_METHOD *
ECDSA_null_method(void)
{
    return &ecdsa_null_method;
}

static const ECDSA_METHOD *default_ecdsa_method = &ecdsa_null_method;

const ECDSA_METHOD *
ECDSA_get_default_method(void)
{
    return default_ecdsa_method;
}

void
ECDSA_set_default_method(const ECDSA_METHOD *meth)
{
    default_ecdsa_method = meth;
}