bufec.c revision 226046
1131722Sobrien/* $OpenBSD: bufec.c,v 1.1 2010/08/31 11:54:45 djm Exp $ */
2218822Sdim/*
3131722Sobrien * Copyright (c) 2010 Damien Miller <djm@mindrot.org>
4131722Sobrien *
5131722Sobrien * Permission to use, copy, modify, and distribute this software for any
6131722Sobrien * purpose with or without fee is hereby granted, provided that the above
7131722Sobrien * copyright notice and this permission notice appear in all copies.
8131722Sobrien *
9131722Sobrien * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10131722Sobrien * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11131722Sobrien * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12131722Sobrien * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13131722Sobrien * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14131722Sobrien * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15131722Sobrien * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16131722Sobrien */
17131722Sobrien
18131722Sobrien#include "includes.h"
19218822Sdim
20131722Sobrien#ifdef OPENSSL_HAS_ECC
21131722Sobrien
22131722Sobrien#include <sys/types.h>
23131722Sobrien
24131722Sobrien#include <openssl/bn.h>
25131722Sobrien#include <openssl/ec.h>
26131722Sobrien
27131722Sobrien#include <string.h>
28131722Sobrien#include <stdarg.h>
29131722Sobrien
30131722Sobrien#include "xmalloc.h"
31131722Sobrien#include "buffer.h"
32131722Sobrien#include "log.h"
33131722Sobrien#include "misc.h"
34131722Sobrien
35131722Sobrien/*
36131722Sobrien * Maximum supported EC GFp field length is 528 bits. SEC1 uncompressed
37131722Sobrien * encoding represents this as two bitstring points that should each
38131722Sobrien * be no longer than the field length, SEC1 specifies a 1 byte
39131722Sobrien * point type header.
40131722Sobrien * Being paranoid here may insulate us to parsing problems in
41131722Sobrien * EC_POINT_oct2point.
42218822Sdim */
43218822Sdim#define BUFFER_MAX_ECPOINT_LEN ((528*2 / 8) + 1)
44218822Sdim
45218822Sdim/*
46218822Sdim * Append an EC_POINT to the buffer as a string containing a SEC1 encoded
47218822Sdim * uncompressed point. Fortunately OpenSSL handles the gory details for us.
48131722Sobrien */
49131722Sobrienint
50131722Sobrienbuffer_put_ecpoint_ret(Buffer *buffer, const EC_GROUP *curve,
51131722Sobrien    const EC_POINT *point)
52131722Sobrien{
53131722Sobrien	u_char *buf = NULL;
54131722Sobrien	size_t len;
55131722Sobrien	BN_CTX *bnctx;
56131722Sobrien	int ret = -1;
57131722Sobrien
58131722Sobrien	/* Determine length */
59131722Sobrien	if ((bnctx = BN_CTX_new()) == NULL)
60131722Sobrien		fatal("%s: BN_CTX_new failed", __func__);
61131722Sobrien	len = EC_POINT_point2oct(curve, point, POINT_CONVERSION_UNCOMPRESSED,
62131722Sobrien	    NULL, 0, bnctx);
63131722Sobrien	if (len > BUFFER_MAX_ECPOINT_LEN) {
64131722Sobrien		error("%s: giant EC point: len = %lu (max %u)",
65131722Sobrien		    __func__, (u_long)len, BUFFER_MAX_ECPOINT_LEN);
66218822Sdim		goto out;
67218822Sdim	}
68131722Sobrien	/* Convert */
69131722Sobrien	buf = xmalloc(len);
70218822Sdim	if (EC_POINT_point2oct(curve, point, POINT_CONVERSION_UNCOMPRESSED,
71218822Sdim	    buf, len, bnctx) != len) {
72131722Sobrien		error("%s: EC_POINT_point2oct length mismatch", __func__);
73131722Sobrien		goto out;
74131722Sobrien	}
75131722Sobrien	/* Append */
76218822Sdim	buffer_put_string(buffer, buf, len);
77131722Sobrien	ret = 0;
78131722Sobrien out:
79131722Sobrien	if (buf != NULL) {
80131722Sobrien		bzero(buf, len);
81218822Sdim		xfree(buf);
82218822Sdim	}
83131722Sobrien	BN_CTX_free(bnctx);
84131722Sobrien	return ret;
85131722Sobrien}
86131722Sobrien
87218822Sdimvoid
88218822Sdimbuffer_put_ecpoint(Buffer *buffer, const EC_GROUP *curve,
89131722Sobrien    const EC_POINT *point)
90131722Sobrien{
91131722Sobrien	if (buffer_put_ecpoint_ret(buffer, curve, point) == -1)
92131722Sobrien		fatal("%s: buffer error", __func__);
93131722Sobrien}
94131722Sobrien
95131722Sobrienint
96131722Sobrienbuffer_get_ecpoint_ret(Buffer *buffer, const EC_GROUP *curve,
97131722Sobrien    EC_POINT *point)
98131722Sobrien{
99131722Sobrien	u_char *buf;
100218822Sdim	u_int len;
101131722Sobrien	BN_CTX *bnctx;
102131722Sobrien	int ret = -1;
103131722Sobrien
104131722Sobrien	if ((buf = buffer_get_string_ret(buffer, &len)) == NULL) {
105131722Sobrien		error("%s: invalid point", __func__);
106131722Sobrien		return -1;
107131722Sobrien	}
108131722Sobrien	if ((bnctx = BN_CTX_new()) == NULL)
109131722Sobrien		fatal("%s: BN_CTX_new failed", __func__);
110131722Sobrien	if (len > BUFFER_MAX_ECPOINT_LEN) {
111131722Sobrien		error("%s: EC_POINT too long: %u > max %u", __func__,
112131722Sobrien		    len, BUFFER_MAX_ECPOINT_LEN);
113218822Sdim		goto out;
114131722Sobrien	}
115131722Sobrien	if (len == 0) {
116131722Sobrien		error("%s: EC_POINT buffer is empty", __func__);
117131722Sobrien		goto out;
118131722Sobrien	}
119131722Sobrien	if (buf[0] != POINT_CONVERSION_UNCOMPRESSED) {
120131722Sobrien		error("%s: EC_POINT is in an incorrect form: "
121131722Sobrien		    "0x%02x (want 0x%02x)", __func__, buf[0],
122131722Sobrien		    POINT_CONVERSION_UNCOMPRESSED);
123131722Sobrien		goto out;
124218822Sdim	}
125218822Sdim	if (EC_POINT_oct2point(curve, point, buf, len, bnctx) != 1) {
126218822Sdim		error("buffer_get_bignum2_ret: BN_bin2bn failed");
127131722Sobrien		goto out;
128131722Sobrien	}
129218822Sdim	/* EC_POINT_oct2point verifies that the point is on the curve for us */
130131722Sobrien	ret = 0;
131131722Sobrien out:
132218822Sdim	BN_CTX_free(bnctx);
133131722Sobrien	bzero(buf, len);
134131722Sobrien	xfree(buf);
135218822Sdim	return ret;
136131722Sobrien}
137131722Sobrien
138218822Sdimvoid
139131722Sobrienbuffer_get_ecpoint(Buffer *buffer, const EC_GROUP *curve,
140131722Sobrien    EC_POINT *point)
141218822Sdim{
142131722Sobrien	if (buffer_get_ecpoint_ret(buffer, curve, point) == -1)
143131722Sobrien		fatal("%s: buffer error", __func__);
144218822Sdim}
145131722Sobrien
146218822Sdim#endif /* OPENSSL_HAS_ECC */
147218822Sdim