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