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