version 1.3, 2014/01/31 16:39:19 |
version 1.4, 2014/04/30 05:29:56 |
|
|
/* $OpenBSD$ */ |
/* $OpenBSD$ */ |
|
|
/* |
/* |
* Copyright (c) 2010 Damien Miller <djm@mindrot.org> |
* Copyright (c) 2012 Damien Miller <djm@mindrot.org> |
* |
* |
* Permission to use, copy, modify, and distribute this software for any |
* Permission to use, copy, modify, and distribute this software for any |
* purpose with or without fee is hereby granted, provided that the above |
* purpose with or without fee is hereby granted, provided that the above |
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
*/ |
*/ |
#include <sys/types.h> |
|
|
|
#include <openssl/bn.h> |
/* Emulation wrappers for legacy OpenSSH buffer API atop sshbuf */ |
#include <openssl/ec.h> |
|
|
|
#include <string.h> |
#include <sys/types.h> |
#include <stdarg.h> |
|
|
|
#include "xmalloc.h" |
|
#include "buffer.h" |
#include "buffer.h" |
#include "log.h" |
#include "log.h" |
#include "misc.h" |
#include "ssherr.h" |
|
|
/* |
|
* Maximum supported EC GFp field length is 528 bits. SEC1 uncompressed |
|
* encoding represents this as two bitstring points that should each |
|
* be no longer than the field length, SEC1 specifies a 1 byte |
|
* point type header. |
|
* Being paranoid here may insulate us to parsing problems in |
|
* EC_POINT_oct2point. |
|
*/ |
|
#define BUFFER_MAX_ECPOINT_LEN ((528*2 / 8) + 1) |
|
|
|
/* |
|
* Append an EC_POINT to the buffer as a string containing a SEC1 encoded |
|
* uncompressed point. Fortunately OpenSSL handles the gory details for us. |
|
*/ |
|
int |
int |
buffer_put_ecpoint_ret(Buffer *buffer, const EC_GROUP *curve, |
buffer_put_ecpoint_ret(Buffer *buffer, const EC_GROUP *curve, |
const EC_POINT *point) |
const EC_POINT *point) |
{ |
{ |
u_char *buf = NULL; |
int ret; |
size_t len; |
|
BN_CTX *bnctx; |
|
int ret = -1; |
|
|
|
/* Determine length */ |
if ((ret = sshbuf_put_ec(buffer, point, curve)) != 0) { |
if ((bnctx = BN_CTX_new()) == NULL) |
error("%s: %s", __func__, ssh_err(ret)); |
fatal("%s: BN_CTX_new failed", __func__); |
return -1; |
len = EC_POINT_point2oct(curve, point, POINT_CONVERSION_UNCOMPRESSED, |
|
NULL, 0, bnctx); |
|
if (len > BUFFER_MAX_ECPOINT_LEN) { |
|
error("%s: giant EC point: len = %lu (max %u)", |
|
__func__, (u_long)len, BUFFER_MAX_ECPOINT_LEN); |
|
goto out; |
|
} |
} |
/* Convert */ |
return 0; |
buf = xmalloc(len); |
|
if (EC_POINT_point2oct(curve, point, POINT_CONVERSION_UNCOMPRESSED, |
|
buf, len, bnctx) != len) { |
|
error("%s: EC_POINT_point2oct length mismatch", __func__); |
|
goto out; |
|
} |
|
/* Append */ |
|
buffer_put_string(buffer, buf, len); |
|
ret = 0; |
|
out: |
|
if (buf != NULL) { |
|
explicit_bzero(buf, len); |
|
free(buf); |
|
} |
|
BN_CTX_free(bnctx); |
|
return ret; |
|
} |
} |
|
|
void |
void |
|
|
buffer_get_ecpoint_ret(Buffer *buffer, const EC_GROUP *curve, |
buffer_get_ecpoint_ret(Buffer *buffer, const EC_GROUP *curve, |
EC_POINT *point) |
EC_POINT *point) |
{ |
{ |
u_char *buf; |
int ret; |
u_int len; |
|
BN_CTX *bnctx; |
|
int ret = -1; |
|
|
|
if ((buf = buffer_get_string_ret(buffer, &len)) == NULL) { |
if ((ret = sshbuf_get_ec(buffer, point, curve)) != 0) { |
error("%s: invalid point", __func__); |
error("%s: %s", __func__, ssh_err(ret)); |
return -1; |
return -1; |
} |
} |
if ((bnctx = BN_CTX_new()) == NULL) |
return 0; |
fatal("%s: BN_CTX_new failed", __func__); |
|
if (len > BUFFER_MAX_ECPOINT_LEN) { |
|
error("%s: EC_POINT too long: %u > max %u", __func__, |
|
len, BUFFER_MAX_ECPOINT_LEN); |
|
goto out; |
|
} |
|
if (len == 0) { |
|
error("%s: EC_POINT buffer is empty", __func__); |
|
goto out; |
|
} |
|
if (buf[0] != POINT_CONVERSION_UNCOMPRESSED) { |
|
error("%s: EC_POINT is in an incorrect form: " |
|
"0x%02x (want 0x%02x)", __func__, buf[0], |
|
POINT_CONVERSION_UNCOMPRESSED); |
|
goto out; |
|
} |
|
if (EC_POINT_oct2point(curve, point, buf, len, bnctx) != 1) { |
|
error("buffer_get_bignum2_ret: BN_bin2bn failed"); |
|
goto out; |
|
} |
|
/* EC_POINT_oct2point verifies that the point is on the curve for us */ |
|
ret = 0; |
|
out: |
|
BN_CTX_free(bnctx); |
|
explicit_bzero(buf, len); |
|
free(buf); |
|
return ret; |
|
} |
} |
|
|
void |
void |
|
|
if (buffer_get_ecpoint_ret(buffer, curve, point) == -1) |
if (buffer_get_ecpoint_ret(buffer, curve, point) == -1) |
fatal("%s: buffer error", __func__); |
fatal("%s: buffer error", __func__); |
} |
} |
|
|
|
|