Annotation of src/usr.bin/ssh/sshbuf-getput-crypto.c, Revision 1.1
1.1 ! djm 1: /* $OpenBSD$ */
! 2: /*
! 3: * Copyright (c) 2011 Damien Miller
! 4: *
! 5: * Permission to use, copy, modify, and distribute this software for any
! 6: * purpose with or without fee is hereby granted, provided that the above
! 7: * copyright notice and this permission notice appear in all copies.
! 8: *
! 9: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
! 10: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
! 11: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
! 12: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
! 13: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
! 14: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
! 15: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
! 16: */
! 17:
! 18: #include <sys/types.h>
! 19: #include <stdlib.h>
! 20: #include <stdio.h>
! 21: #include <string.h>
! 22:
! 23: #include <openssl/bn.h>
! 24: #include <openssl/ec.h>
! 25:
! 26: #include "ssherr.h"
! 27: #define SSHBUF_INTERNAL
! 28: #include "sshbuf.h"
! 29:
! 30: int
! 31: sshbuf_get_bignum2(struct sshbuf *buf, BIGNUM *v)
! 32: {
! 33: const u_char *d;
! 34: size_t len;
! 35: int r;
! 36:
! 37: if ((r = sshbuf_peek_string_direct(buf, &d, &len)) < 0)
! 38: return r;
! 39: /* Refuse negative (MSB set) and overlong bignums */
! 40: if ((len != 0 && (*d & 0x80) != 0))
! 41: return SSH_ERR_BIGNUM_IS_NEGATIVE;
! 42: if (len > SSHBUF_MAX_BIGNUM)
! 43: return SSH_ERR_BIGNUM_TOO_LARGE;
! 44: if (v != NULL && BN_bin2bn(d, len, v) == NULL)
! 45: return SSH_ERR_ALLOC_FAIL;
! 46: /* Consume the string */
! 47: if (sshbuf_get_string_direct(buf, NULL, NULL) != 0) {
! 48: /* Shouldn't happen */
! 49: SSHBUF_DBG(("SSH_ERR_INTERNAL_ERROR"));
! 50: SSHBUF_ABORT();
! 51: return SSH_ERR_INTERNAL_ERROR;
! 52: }
! 53: return 0;
! 54: }
! 55:
! 56: int
! 57: sshbuf_get_bignum1(struct sshbuf *buf, BIGNUM *v)
! 58: {
! 59: const u_char *d = sshbuf_ptr(buf);
! 60: u_int16_t len_bits;
! 61: size_t len_bytes;
! 62:
! 63: /* Length in bits */
! 64: if (sshbuf_len(buf) < 2)
! 65: return SSH_ERR_MESSAGE_INCOMPLETE;
! 66: len_bits = PEEK_U16(d);
! 67: len_bytes = (len_bits + 7) >> 3;
! 68: if (len_bytes > SSHBUF_MAX_BIGNUM + 1)
! 69: return SSH_ERR_BIGNUM_TOO_LARGE;
! 70: if (sshbuf_len(buf) < 2 + len_bytes)
! 71: return SSH_ERR_MESSAGE_INCOMPLETE;
! 72: if (v != NULL && BN_bin2bn(d + 2, len_bytes, v) == NULL)
! 73: return SSH_ERR_ALLOC_FAIL;
! 74: if (sshbuf_consume(buf, 2 + len_bytes) != 0) {
! 75: SSHBUF_DBG(("SSH_ERR_INTERNAL_ERROR"));
! 76: SSHBUF_ABORT();
! 77: return SSH_ERR_INTERNAL_ERROR;
! 78: }
! 79: return 0;
! 80: }
! 81:
! 82: static int
! 83: get_ec(const u_char *d, size_t len, EC_POINT *v, const EC_GROUP *g)
! 84: {
! 85: /* Refuse overlong bignums */
! 86: if (len == 0 || len > SSHBUF_MAX_ECPOINT)
! 87: return SSH_ERR_ECPOINT_TOO_LARGE;
! 88: /* Only handle uncompressed points */
! 89: if (*d != POINT_CONVERSION_UNCOMPRESSED)
! 90: return SSH_ERR_INVALID_FORMAT;
! 91: if (v != NULL && EC_POINT_oct2point(g, v, d, len, NULL) != 1)
! 92: return SSH_ERR_INVALID_FORMAT; /* XXX assumption */
! 93: return 0;
! 94: }
! 95:
! 96: int
! 97: sshbuf_get_ec(struct sshbuf *buf, EC_POINT *v, const EC_GROUP *g)
! 98: {
! 99: const u_char *d;
! 100: size_t len;
! 101: int r;
! 102:
! 103: if ((r = sshbuf_peek_string_direct(buf, &d, &len)) < 0)
! 104: return r;
! 105: if ((r = get_ec(d, len, v, g)) != 0)
! 106: return r;
! 107: /* Skip string */
! 108: if (sshbuf_get_string_direct(buf, NULL, NULL) != 0) {
! 109: /* Shouldn't happen */
! 110: SSHBUF_DBG(("SSH_ERR_INTERNAL_ERROR"));
! 111: SSHBUF_ABORT();
! 112: return SSH_ERR_INTERNAL_ERROR;
! 113: }
! 114: return 0;
! 115: }
! 116:
! 117: int
! 118: sshbuf_get_eckey(struct sshbuf *buf, EC_KEY *v)
! 119: {
! 120: EC_POINT *pt = EC_POINT_new(EC_KEY_get0_group(v));
! 121: int r;
! 122: const u_char *d;
! 123: size_t len;
! 124:
! 125: if (pt == NULL) {
! 126: SSHBUF_DBG(("SSH_ERR_ALLOC_FAIL"));
! 127: return SSH_ERR_ALLOC_FAIL;
! 128: }
! 129: if ((r = sshbuf_peek_string_direct(buf, &d, &len)) < 0) {
! 130: EC_POINT_free(pt);
! 131: return r;
! 132: }
! 133: if ((r = get_ec(d, len, pt, EC_KEY_get0_group(v))) != 0) {
! 134: EC_POINT_free(pt);
! 135: return r;
! 136: }
! 137: if (EC_KEY_set_public_key(v, pt) != 1) {
! 138: EC_POINT_free(pt);
! 139: return SSH_ERR_ALLOC_FAIL; /* XXX assumption */
! 140: }
! 141: EC_POINT_free(pt);
! 142: /* Skip string */
! 143: if (sshbuf_get_string_direct(buf, NULL, NULL) != 0) {
! 144: /* Shouldn't happen */
! 145: SSHBUF_DBG(("SSH_ERR_INTERNAL_ERROR"));
! 146: SSHBUF_ABORT();
! 147: return SSH_ERR_INTERNAL_ERROR;
! 148: }
! 149: return 0;
! 150: }
! 151:
! 152: int
! 153: sshbuf_put_bignum2(struct sshbuf *buf, const BIGNUM *v)
! 154: {
! 155: u_char d[SSHBUF_MAX_BIGNUM + 1];
! 156: int len = BN_num_bytes(v), prepend = 0, r;
! 157:
! 158: if (len < 0 || len > SSHBUF_MAX_BIGNUM)
! 159: return SSH_ERR_INVALID_ARGUMENT;
! 160: *d = '\0';
! 161: if (BN_bn2bin(v, d + 1) != len)
! 162: return SSH_ERR_INTERNAL_ERROR; /* Shouldn't happen */
! 163: /* If MSB is set, prepend a \0 */
! 164: if (len > 0 && (d[1] & 0x80) != 0)
! 165: prepend = 1;
! 166: if ((r = sshbuf_put_string(buf, d + 1 - prepend, len + prepend)) < 0) {
! 167: bzero(d, sizeof(d));
! 168: return r;
! 169: }
! 170: bzero(d, sizeof(d));
! 171: return 0;
! 172: }
! 173:
! 174: int
! 175: sshbuf_put_bignum1(struct sshbuf *buf, const BIGNUM *v)
! 176: {
! 177: int r, len_bits = BN_num_bits(v);
! 178: size_t len_bytes = (len_bits + 7) / 8;
! 179: u_char d[SSHBUF_MAX_BIGNUM], *dp;
! 180:
! 181: if (len_bits < 0 || len_bytes > SSHBUF_MAX_BIGNUM)
! 182: return SSH_ERR_INVALID_ARGUMENT;
! 183: if (BN_bn2bin(v, d) != (int)len_bytes)
! 184: return SSH_ERR_INTERNAL_ERROR; /* Shouldn't happen */
! 185: if ((r = sshbuf_reserve(buf, len_bytes + 2, &dp)) < 0) {
! 186: bzero(d, sizeof(d));
! 187: return r;
! 188: }
! 189: POKE_U16(dp, len_bits);
! 190: memcpy(dp + 2, d, len_bytes);
! 191: bzero(d, sizeof(d));
! 192: return 0;
! 193: }
! 194:
! 195: int
! 196: sshbuf_put_ec(struct sshbuf *buf, const EC_POINT *v, const EC_GROUP *g)
! 197: {
! 198: u_char d[SSHBUF_MAX_ECPOINT];
! 199: BN_CTX *bn_ctx;
! 200: size_t len;
! 201: int ret;
! 202:
! 203: if ((bn_ctx = BN_CTX_new()) == NULL)
! 204: return SSH_ERR_ALLOC_FAIL;
! 205: if ((len = EC_POINT_point2oct(g, v, POINT_CONVERSION_UNCOMPRESSED,
! 206: NULL, 0, bn_ctx)) > SSHBUF_MAX_ECPOINT) {
! 207: BN_CTX_free(bn_ctx);
! 208: return SSH_ERR_INVALID_ARGUMENT;
! 209: }
! 210: if (EC_POINT_point2oct(g, v, POINT_CONVERSION_UNCOMPRESSED,
! 211: d, len, bn_ctx) != len) {
! 212: BN_CTX_free(bn_ctx);
! 213: return SSH_ERR_INTERNAL_ERROR; /* Shouldn't happen */
! 214: }
! 215: BN_CTX_free(bn_ctx);
! 216: ret = sshbuf_put_string(buf, d, len);
! 217: bzero(d, len);
! 218: return ret;
! 219: }
! 220:
! 221: int
! 222: sshbuf_put_eckey(struct sshbuf *buf, const EC_KEY *v)
! 223: {
! 224: return sshbuf_put_ec(buf, EC_KEY_get0_public_key(v),
! 225: EC_KEY_get0_group(v));
! 226: }
! 227: