bufec.c revision 221420
11541Srgrimes/* $OpenBSD: bufec.c,v 1.1 2010/08/31 11:54:45 djm Exp $ */
21541Srgrimes/*
31541Srgrimes * Copyright (c) 2010 Damien Miller <djm@mindrot.org>
41541Srgrimes *
51541Srgrimes * Permission to use, copy, modify, and distribute this software for any
61541Srgrimes * purpose with or without fee is hereby granted, provided that the above
71541Srgrimes * copyright notice and this permission notice appear in all copies.
81541Srgrimes *
91541Srgrimes * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
101541Srgrimes * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
111541Srgrimes * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
121541Srgrimes * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
131541Srgrimes * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
141541Srgrimes * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
151541Srgrimes * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
161541Srgrimes */
171541Srgrimes
181541Srgrimes#include "includes.h"
191541Srgrimes
201541Srgrimes#ifdef OPENSSL_HAS_ECC
211541Srgrimes
221541Srgrimes#include <sys/types.h>
231541Srgrimes
241541Srgrimes#include <openssl/bn.h>
251541Srgrimes#include <openssl/ec.h>
261541Srgrimes
271541Srgrimes#include <string.h>
281541Srgrimes#include <stdarg.h>
291541Srgrimes
301541Srgrimes#include "xmalloc.h"
311541Srgrimes#include "buffer.h"
321541Srgrimes#include "log.h"
331541Srgrimes#include "misc.h"
341541Srgrimes
351541Srgrimes/*
36116182Sobrien * Maximum supported EC GFp field length is 528 bits. SEC1 uncompressed
37116182Sobrien * encoding represents this as two bitstring points that should each
38116182Sobrien * be no longer than the field length, SEC1 specifies a 1 byte
3931778Seivind * point type header.
4031778Seivind * Being paranoid here may insulate us to parsing problems in
411541Srgrimes * EC_POINT_oct2point.
421541Srgrimes */
4312221Sbde#define BUFFER_MAX_ECPOINT_LEN ((528*2 / 8) + 1)
441541Srgrimes
451541Srgrimes/*
4682717Sdillon * Append an EC_POINT to the buffer as a string containing a SEC1 encoded
4782717Sdillon * uncompressed point. Fortunately OpenSSL handles the gory details for us.
481541Srgrimes */
491549Srgrimesint
501541Srgrimesbuffer_put_ecpoint_ret(Buffer *buffer, const EC_GROUP *curve,
518876Srgrimes    const EC_POINT *point)
521541Srgrimes{
531541Srgrimes	u_char *buf = NULL;
5412221Sbde	size_t len;
551541Srgrimes	BN_CTX *bnctx;
561541Srgrimes	int ret = -1;
571541Srgrimes
581541Srgrimes	/* Determine length */
5912221Sbde	if ((bnctx = BN_CTX_new()) == NULL)
6082717Sdillon		fatal("%s: BN_CTX_new failed", __func__);
6182717Sdillon	len = EC_POINT_point2oct(curve, point, POINT_CONVERSION_UNCOMPRESSED,
6282717Sdillon	    NULL, 0, bnctx);
631541Srgrimes	if (len > BUFFER_MAX_ECPOINT_LEN) {
641549Srgrimes		error("%s: giant EC point: len = %lu (max %u)",
6583366Sjulian		    __func__, (u_long)len, BUFFER_MAX_ECPOINT_LEN);
6683366Sjulian		goto out;
671541Srgrimes	}
681541Srgrimes	/* Convert */
6912171Sphk	buf = xmalloc(len);
7082717Sdillon	if (EC_POINT_point2oct(curve, point, POINT_CONVERSION_UNCOMPRESSED,
7138517Sdfr	    buf, len, bnctx) != len) {
721541Srgrimes		error("%s: EC_POINT_point2oct length mismatch", __func__);
7312171Sphk		goto out;
7412171Sphk	}
7582717Sdillon	/* Append */
7683366Sjulian	buffer_put_string(buffer, buf, len);
7782717Sdillon	ret = 0;
7882717Sdillon out:
791541Srgrimes	if (buf != NULL) {
801541Srgrimes		bzero(buf, len);
8112221Sbde		xfree(buf);
821541Srgrimes	}
831541Srgrimes	BN_CTX_free(bnctx);
841541Srgrimes	return ret;
851541Srgrimes}
8612221Sbde
8782717Sdillonvoid
8882717Sdillonbuffer_put_ecpoint(Buffer *buffer, const EC_GROUP *curve,
8982717Sdillon    const EC_POINT *point)
901541Srgrimes{
911549Srgrimes	if (buffer_put_ecpoint_ret(buffer, curve, point) == -1)
9283366Sjulian		fatal("%s: buffer error", __func__);
9383366Sjulian}
941541Srgrimes
951541Srgrimesint
9612171Sphkbuffer_get_ecpoint_ret(Buffer *buffer, const EC_GROUP *curve,
971541Srgrimes    EC_POINT *point)
981541Srgrimes{
9912171Sphk	u_char *buf;
10012171Sphk	u_int len;
10182717Sdillon	BN_CTX *bnctx;
10293593Sjhb	int ret = -1;
10383366Sjulian
10482717Sdillon	if ((buf = buffer_get_string_ret(buffer, &len)) == NULL) {
10582717Sdillon		error("%s: invalid point", __func__);
10682717Sdillon		return -1;
10782717Sdillon	}
1081541Srgrimes	if ((bnctx = BN_CTX_new()) == NULL)
1091541Srgrimes		fatal("%s: BN_CTX_new failed", __func__);
11012221Sbde	if (len > BUFFER_MAX_ECPOINT_LEN) {
11112200Sbde		error("%s: EC_POINT too long: %u > max %u", __func__,
1121541Srgrimes		    len, BUFFER_MAX_ECPOINT_LEN);
1131541Srgrimes		goto out;
11412221Sbde	}
11582717Sdillon	if (len == 0) {
11682717Sdillon		error("%s: EC_POINT buffer is empty", __func__);
11782717Sdillon		goto out;
1181541Srgrimes	}
1191549Srgrimes	if (buf[0] != POINT_CONVERSION_UNCOMPRESSED) {
12083366Sjulian		error("%s: EC_POINT is in an incorrect form: "
12183366Sjulian		    "0x%02x (want 0x%02x)", __func__, buf[0],
12212200Sbde		    POINT_CONVERSION_UNCOMPRESSED);
1231541Srgrimes		goto out;
1241541Srgrimes	}
12583366Sjulian	if (EC_POINT_oct2point(curve, point, buf, len, bnctx) != 1) {
1261541Srgrimes		error("buffer_get_bignum2_ret: BN_bin2bn failed");
1271541Srgrimes		goto out;
1281541Srgrimes	}
1291541Srgrimes	/* EC_POINT_oct2point verifies that the point is on the curve for us */
1301541Srgrimes	ret = 0;
13112221Sbde out:
13212200Sbde	BN_CTX_free(bnctx);
1331541Srgrimes	bzero(buf, len);
1341541Srgrimes	xfree(buf);
13512221Sbde	return ret;
13682717Sdillon}
13782717Sdillon
13882717Sdillonvoid
1391541Srgrimesbuffer_get_ecpoint(Buffer *buffer, const EC_GROUP *curve,
1401549Srgrimes    EC_POINT *point)
14183366Sjulian{
14283366Sjulian	if (buffer_get_ecpoint_ret(buffer, curve, point) == -1)
14312200Sbde		fatal("%s: buffer error", __func__);
1441541Srgrimes}
1451541Srgrimes
1461541Srgrimes#endif /* OPENSSL_HAS_ECC */
14782717Sdillon