OpenBSD-4.6/usr.bin/gzsig/key.c

Compare this file to the similar file:
Show the results in this format:

/* $OpenBSD: key.c,v 1.5 2006/04/03 01:33:09 djm Exp $ */

/*
 * key.c
 *
 * Copyright (c) 2001 Dug Song <dugsong@arbor.net>
 * Copyright (c) 2001 Arbor Networks, Inc.
 *
 *   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. The names of the copyright holders may not be used to endorse or
 *      promote products derived from this software without specific
 *      prior written permission.
 * 
 *   THIS SOFTWARE IS PROVIDED ``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 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.
 *
 * $Vendor: key.c,v 1.2 2005/04/01 16:47:31 dugsong Exp $
 */

#include <sys/limits.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/uio.h>

#include <openssl/ssl.h>

#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#include "key.h"
#include "ssh.h"
#include "ssh2.h"
#include "util.h"
#include "x509.h"

typedef int (*key_loader)(struct key *, struct iovec *);

static key_loader pubkey_loaders[] = {
	ssh_load_public,
	ssh2_load_public,
	x509_load_public,
	NULL
};

static key_loader privkey_loaders[] = {
	ssh_load_private,
	x509_load_private,
	NULL
};

static int
load_file(struct iovec *iov, char *filename)
{
	struct stat st;
	int fd;
	
	if ((fd = open(filename, O_RDONLY)) < 0)
		return (-1);
	
	if (fstat(fd, &st) < 0)
		return (-1);
	
	if (st.st_size == 0 || st.st_size >= SIZE_MAX) {
		errno = EINVAL;
		return (-1);
	}
	if ((iov->iov_base = malloc(st.st_size + 1)) == NULL)
		return (-1);

	iov->iov_len = st.st_size;
	((u_char *)iov->iov_base)[iov->iov_len] = '\0';
	
	if (read(fd, iov->iov_base, iov->iov_len) != iov->iov_len) {
		free(iov->iov_base);
		return (-1);
	}
	close(fd);
	
	return (0);
}

struct key *
key_new(void)
{
	return (calloc(1, sizeof(struct key)));
}

int
key_load_private(struct key *k, char *filename)
{
	struct iovec iov;
	int i;
	
	if (load_file(&iov, filename) < 0)
		return (-1);

	for (i = 0; privkey_loaders[i] != NULL; i++) {
		if (privkey_loaders[i](k, &iov) == 0)
			return (0);
	}
	return (-1);
}

int
key_load_public(struct key *k, char *filename)
{
	struct iovec iov;
	int i;

	if (load_file(&iov, filename) < 0)
		return (-1);

	for (i = 0; pubkey_loaders[i] != NULL; i++) {
		if (pubkey_loaders[i](k, &iov) == 0)
			return (0);
	}
	return (-1);
}

int
key_sign(struct key *k, u_char *msg, int mlen, u_char *sig, int slen)
{
	switch (k->type) {
	case KEY_RSA:
		if (RSA_size((RSA *)k->data) > slen) {
			fprintf(stderr, "RSA modulus too large: %d bits\n",
			    RSA_size((RSA *)k->data));
			return (-1);
		}
		if (RSA_sign(NID_sha1, msg, mlen, sig, &slen,
		    (RSA *)k->data) <= 0) {
			fprintf(stderr, "RSA signing failed\n");
			return (-1);
		}
		break;

	case KEY_DSA:
		if (DSA_size((DSA *)k->data) > slen) {
			fprintf(stderr, "DSA signature size too large: "
			    "%d bits\n", DSA_size((DSA *)k->data));
			return (-1);
		}
		if (DSA_sign(NID_sha1, msg, mlen, sig, &slen,
		    (DSA *)k->data) <= 0) {
			fprintf(stderr, "DSA signing failed\n");
			return (-1);
		}
		break;

	default:
		fprintf(stderr, "Unknown key type: %d\n", k->type);
		return (-1);
	}
	return (slen);
}

int
key_verify(struct key *k, u_char *msg, int mlen, u_char *sig, int slen)
{
	switch (k->type) {

	case KEY_RSA:
		if (RSA_verify(NID_sha1, msg, mlen,
		    sig, slen, (RSA *)k->data) <= 0) {
			fprintf(stderr, "RSA verification failed\n");
			return (-1);
		}
		break;

	case KEY_DSA:
		if (DSA_verify(NID_sha1, msg, mlen,
		    sig, slen, (DSA *)k->data) <= 0) {
			fprintf(stderr, "DSA verification failed\n");
			return (-1);
		}
		break;

	default:
		fprintf(stderr, "Unknown key type: %d\n", k->type);
		return (-1);
	}
	return (slen);
}

void
key_free(struct key *k)
{
	if (k->type == KEY_RSA)
		RSA_free((RSA *)k->data);
	else if (k->type == KEY_DSA)
		DSA_free((DSA *)k->data);
	else if (k->data != NULL)
		free(k->data);
	
	free(k);
}