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