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