1255767Sdes/* $OpenBSD: bufec.c,v 1.2 2013/05/17 00:13:13 djm Exp $ */ 2218767Sdes/* 3218767Sdes * Copyright (c) 2010 Damien Miller <djm@mindrot.org> 4218767Sdes * 5218767Sdes * Permission to use, copy, modify, and distribute this software for any 6218767Sdes * purpose with or without fee is hereby granted, provided that the above 7218767Sdes * copyright notice and this permission notice appear in all copies. 8218767Sdes * 9218767Sdes * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10218767Sdes * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11218767Sdes * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12218767Sdes * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13218767Sdes * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14218767Sdes * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15218767Sdes * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16218767Sdes */ 17218767Sdes 18218767Sdes#include "includes.h" 19218767Sdes 20218767Sdes#ifdef OPENSSL_HAS_ECC 21218767Sdes 22218767Sdes#include <sys/types.h> 23218767Sdes 24218767Sdes#include <openssl/bn.h> 25218767Sdes#include <openssl/ec.h> 26218767Sdes 27218767Sdes#include <string.h> 28218767Sdes#include <stdarg.h> 29218767Sdes 30218767Sdes#include "xmalloc.h" 31218767Sdes#include "buffer.h" 32218767Sdes#include "log.h" 33218767Sdes#include "misc.h" 34218767Sdes 35218767Sdes/* 36218767Sdes * Maximum supported EC GFp field length is 528 bits. SEC1 uncompressed 37218767Sdes * encoding represents this as two bitstring points that should each 38218767Sdes * be no longer than the field length, SEC1 specifies a 1 byte 39218767Sdes * point type header. 40218767Sdes * Being paranoid here may insulate us to parsing problems in 41218767Sdes * EC_POINT_oct2point. 42218767Sdes */ 43218767Sdes#define BUFFER_MAX_ECPOINT_LEN ((528*2 / 8) + 1) 44218767Sdes 45218767Sdes/* 46218767Sdes * Append an EC_POINT to the buffer as a string containing a SEC1 encoded 47218767Sdes * uncompressed point. Fortunately OpenSSL handles the gory details for us. 48218767Sdes */ 49218767Sdesint 50218767Sdesbuffer_put_ecpoint_ret(Buffer *buffer, const EC_GROUP *curve, 51218767Sdes const EC_POINT *point) 52218767Sdes{ 53218767Sdes u_char *buf = NULL; 54218767Sdes size_t len; 55218767Sdes BN_CTX *bnctx; 56218767Sdes int ret = -1; 57218767Sdes 58218767Sdes /* Determine length */ 59218767Sdes if ((bnctx = BN_CTX_new()) == NULL) 60218767Sdes fatal("%s: BN_CTX_new failed", __func__); 61218767Sdes len = EC_POINT_point2oct(curve, point, POINT_CONVERSION_UNCOMPRESSED, 62218767Sdes NULL, 0, bnctx); 63218767Sdes if (len > BUFFER_MAX_ECPOINT_LEN) { 64218767Sdes error("%s: giant EC point: len = %lu (max %u)", 65218767Sdes __func__, (u_long)len, BUFFER_MAX_ECPOINT_LEN); 66218767Sdes goto out; 67218767Sdes } 68218767Sdes /* Convert */ 69218767Sdes buf = xmalloc(len); 70218767Sdes if (EC_POINT_point2oct(curve, point, POINT_CONVERSION_UNCOMPRESSED, 71218767Sdes buf, len, bnctx) != len) { 72218767Sdes error("%s: EC_POINT_point2oct length mismatch", __func__); 73218767Sdes goto out; 74218767Sdes } 75218767Sdes /* Append */ 76218767Sdes buffer_put_string(buffer, buf, len); 77218767Sdes ret = 0; 78218767Sdes out: 79218767Sdes if (buf != NULL) { 80218767Sdes bzero(buf, len); 81255767Sdes free(buf); 82218767Sdes } 83218767Sdes BN_CTX_free(bnctx); 84218767Sdes return ret; 85218767Sdes} 86218767Sdes 87218767Sdesvoid 88218767Sdesbuffer_put_ecpoint(Buffer *buffer, const EC_GROUP *curve, 89218767Sdes const EC_POINT *point) 90218767Sdes{ 91218767Sdes if (buffer_put_ecpoint_ret(buffer, curve, point) == -1) 92218767Sdes fatal("%s: buffer error", __func__); 93218767Sdes} 94218767Sdes 95218767Sdesint 96218767Sdesbuffer_get_ecpoint_ret(Buffer *buffer, const EC_GROUP *curve, 97218767Sdes EC_POINT *point) 98218767Sdes{ 99218767Sdes u_char *buf; 100218767Sdes u_int len; 101218767Sdes BN_CTX *bnctx; 102218767Sdes int ret = -1; 103218767Sdes 104218767Sdes if ((buf = buffer_get_string_ret(buffer, &len)) == NULL) { 105218767Sdes error("%s: invalid point", __func__); 106218767Sdes return -1; 107218767Sdes } 108218767Sdes if ((bnctx = BN_CTX_new()) == NULL) 109218767Sdes fatal("%s: BN_CTX_new failed", __func__); 110218767Sdes if (len > BUFFER_MAX_ECPOINT_LEN) { 111218767Sdes error("%s: EC_POINT too long: %u > max %u", __func__, 112218767Sdes len, BUFFER_MAX_ECPOINT_LEN); 113218767Sdes goto out; 114218767Sdes } 115218767Sdes if (len == 0) { 116218767Sdes error("%s: EC_POINT buffer is empty", __func__); 117218767Sdes goto out; 118218767Sdes } 119218767Sdes if (buf[0] != POINT_CONVERSION_UNCOMPRESSED) { 120218767Sdes error("%s: EC_POINT is in an incorrect form: " 121218767Sdes "0x%02x (want 0x%02x)", __func__, buf[0], 122218767Sdes POINT_CONVERSION_UNCOMPRESSED); 123218767Sdes goto out; 124218767Sdes } 125218767Sdes if (EC_POINT_oct2point(curve, point, buf, len, bnctx) != 1) { 126218767Sdes error("buffer_get_bignum2_ret: BN_bin2bn failed"); 127218767Sdes goto out; 128218767Sdes } 129218767Sdes /* EC_POINT_oct2point verifies that the point is on the curve for us */ 130218767Sdes ret = 0; 131218767Sdes out: 132218767Sdes BN_CTX_free(bnctx); 133218767Sdes bzero(buf, len); 134255767Sdes free(buf); 135218767Sdes return ret; 136218767Sdes} 137218767Sdes 138218767Sdesvoid 139218767Sdesbuffer_get_ecpoint(Buffer *buffer, const EC_GROUP *curve, 140218767Sdes EC_POINT *point) 141218767Sdes{ 142218767Sdes if (buffer_get_ecpoint_ret(buffer, curve, point) == -1) 143218767Sdes fatal("%s: buffer error", __func__); 144218767Sdes} 145218767Sdes 146218767Sdes#endif /* OPENSSL_HAS_ECC */ 147