11305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood/* $OpenBSD: bufec.c,v 1.1 2010/08/31 11:54:45 djm Exp $ */
21305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood/*
31305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * Copyright (c) 2010 Damien Miller <djm@mindrot.org>
41305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood *
51305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * Permission to use, copy, modify, and distribute this software for any
61305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * purpose with or without fee is hereby granted, provided that the above
71305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * copyright notice and this permission notice appear in all copies.
81305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood *
91305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
101305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
111305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
121305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
131305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
141305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
151305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
161305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood */
171305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
181305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include "includes.h"
191305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
201305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#ifdef OPENSSL_HAS_ECC
211305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
221305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include <sys/types.h>
231305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
241305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include <openssl/bn.h>
251305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include <openssl/ec.h>
261305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
271305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include <string.h>
281305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include <stdarg.h>
291305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
301305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include "xmalloc.h"
311305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include "buffer.h"
321305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include "log.h"
331305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include "misc.h"
341305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
351305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood/*
361305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * Maximum supported EC GFp field length is 528 bits. SEC1 uncompressed
371305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * encoding represents this as two bitstring points that should each
381305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * be no longer than the field length, SEC1 specifies a 1 byte
391305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * point type header.
401305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * Being paranoid here may insulate us to parsing problems in
411305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * EC_POINT_oct2point.
421305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood */
431305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#define BUFFER_MAX_ECPOINT_LEN ((528*2 / 8) + 1)
441305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
451305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood/*
461305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * Append an EC_POINT to the buffer as a string containing a SEC1 encoded
471305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * uncompressed point. Fortunately OpenSSL handles the gory details for us.
481305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood */
491305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodint
501305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodbuffer_put_ecpoint_ret(Buffer *buffer, const EC_GROUP *curve,
511305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood    const EC_POINT *point)
521305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{
531305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	u_char *buf = NULL;
541305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	size_t len;
551305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	BN_CTX *bnctx;
561305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	int ret = -1;
571305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
581305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	/* Determine length */
591305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if ((bnctx = BN_CTX_new()) == NULL)
601305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		fatal("%s: BN_CTX_new failed", __func__);
611305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	len = EC_POINT_point2oct(curve, point, POINT_CONVERSION_UNCOMPRESSED,
621305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	    NULL, 0, bnctx);
631305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (len > BUFFER_MAX_ECPOINT_LEN) {
641305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		error("%s: giant EC point: len = %lu (max %u)",
651305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		    __func__, (u_long)len, BUFFER_MAX_ECPOINT_LEN);
661305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		goto out;
671305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	}
681305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	/* Convert */
691305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	buf = xmalloc(len);
701305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (EC_POINT_point2oct(curve, point, POINT_CONVERSION_UNCOMPRESSED,
711305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	    buf, len, bnctx) != len) {
721305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		error("%s: EC_POINT_point2oct length mismatch", __func__);
731305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		goto out;
741305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	}
751305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	/* Append */
761305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	buffer_put_string(buffer, buf, len);
771305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	ret = 0;
781305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood out:
791305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (buf != NULL) {
801305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		bzero(buf, len);
811305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		xfree(buf);
821305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	}
831305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	BN_CTX_free(bnctx);
841305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	return ret;
851305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood}
861305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
871305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodvoid
881305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodbuffer_put_ecpoint(Buffer *buffer, const EC_GROUP *curve,
891305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood    const EC_POINT *point)
901305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{
911305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (buffer_put_ecpoint_ret(buffer, curve, point) == -1)
921305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		fatal("%s: buffer error", __func__);
931305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood}
941305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
951305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodint
961305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodbuffer_get_ecpoint_ret(Buffer *buffer, const EC_GROUP *curve,
971305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood    EC_POINT *point)
981305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{
991305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	u_char *buf;
1001305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	u_int len;
1011305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	BN_CTX *bnctx;
1021305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	int ret = -1;
1031305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
1041305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if ((buf = buffer_get_string_ret(buffer, &len)) == NULL) {
1051305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		error("%s: invalid point", __func__);
1061305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		return -1;
1071305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	}
1081305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if ((bnctx = BN_CTX_new()) == NULL)
1091305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		fatal("%s: BN_CTX_new failed", __func__);
1101305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (len > BUFFER_MAX_ECPOINT_LEN) {
1111305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		error("%s: EC_POINT too long: %u > max %u", __func__,
1121305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		    len, BUFFER_MAX_ECPOINT_LEN);
1131305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		goto out;
1141305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	}
1151305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (len == 0) {
1161305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		error("%s: EC_POINT buffer is empty", __func__);
1171305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		goto out;
1181305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	}
1191305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (buf[0] != POINT_CONVERSION_UNCOMPRESSED) {
1201305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		error("%s: EC_POINT is in an incorrect form: "
1211305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		    "0x%02x (want 0x%02x)", __func__, buf[0],
1221305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		    POINT_CONVERSION_UNCOMPRESSED);
1231305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		goto out;
1241305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	}
1251305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (EC_POINT_oct2point(curve, point, buf, len, bnctx) != 1) {
1261305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		error("buffer_get_bignum2_ret: BN_bin2bn failed");
1271305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		goto out;
1281305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	}
1291305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	/* EC_POINT_oct2point verifies that the point is on the curve for us */
1301305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	ret = 0;
1311305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood out:
1321305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	BN_CTX_free(bnctx);
1331305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	bzero(buf, len);
1341305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	xfree(buf);
1351305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	return ret;
1361305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood}
1371305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
1381305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodvoid
1391305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodbuffer_get_ecpoint(Buffer *buffer, const EC_GROUP *curve,
1401305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood    EC_POINT *point)
1411305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{
1421305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (buffer_get_ecpoint_ret(buffer, curve, point) == -1)
1431305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		fatal("%s: buffer error", __func__);
1441305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood}
1451305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
1461305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#endif /* OPENSSL_HAS_ECC */
147