1/* $OpenBSD: sshbuf-getput-crypto.c,v 1.10 2022/05/25 06:03:44 djm Exp $ */ 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#include "includes.h" 18__RCSID("$NetBSD: sshbuf-getput-crypto.c,v 1.11 2022/10/05 22:39:36 christos Exp $"); 19 20#include <sys/types.h> 21#include <stdlib.h> 22#include <stdio.h> 23#include <string.h> 24 25#include <openssl/bn.h> 26#include <openssl/ec.h> 27 28#include "ssherr.h" 29#define SSHBUF_INTERNAL 30#include "sshbuf.h" 31 32int 33sshbuf_get_bignum2(struct sshbuf *buf, BIGNUM **valp) 34{ 35 BIGNUM *v; 36 const u_char *d; 37 size_t len; 38 int r; 39 40 if (valp != NULL) 41 *valp = NULL; 42 if ((r = sshbuf_get_bignum2_bytes_direct(buf, &d, &len)) != 0) 43 return r; 44 if (valp != NULL) { 45 if ((v = BN_new()) == NULL || 46 BN_bin2bn(d, len, v) == NULL) { 47 BN_clear_free(v); 48 return SSH_ERR_ALLOC_FAIL; 49 } 50 *valp = v; 51 } 52 return 0; 53} 54 55static int 56get_ec(const u_char *d, size_t len, EC_POINT *v, const EC_GROUP *g) 57{ 58 /* Refuse overlong bignums */ 59 if (len == 0 || len > SSHBUF_MAX_ECPOINT) 60 return SSH_ERR_ECPOINT_TOO_LARGE; 61 /* Only handle uncompressed points */ 62 if (*d != POINT_CONVERSION_UNCOMPRESSED) 63 return SSH_ERR_INVALID_FORMAT; 64 if (v != NULL && EC_POINT_oct2point(g, v, d, len, NULL) != 1) 65 return SSH_ERR_INVALID_FORMAT; /* XXX assumption */ 66 return 0; 67} 68 69int 70sshbuf_get_ec(struct sshbuf *buf, EC_POINT *v, const EC_GROUP *g) 71{ 72 const u_char *d; 73 size_t len; 74 int r; 75 76 if ((r = sshbuf_peek_string_direct(buf, &d, &len)) < 0) 77 return r; 78 if ((r = get_ec(d, len, v, g)) != 0) 79 return r; 80 /* Skip string */ 81 if (sshbuf_get_string_direct(buf, NULL, NULL) != 0) { 82 /* Shouldn't happen */ 83 SSHBUF_DBG(("SSH_ERR_INTERNAL_ERROR")); 84 SSHBUF_ABORT(); 85 return SSH_ERR_INTERNAL_ERROR; 86 } 87 return 0; 88} 89 90int 91sshbuf_get_eckey(struct sshbuf *buf, EC_KEY *v) 92{ 93 EC_POINT *pt = EC_POINT_new(EC_KEY_get0_group(v)); 94 int r; 95 const u_char *d; 96 size_t len; 97 98 if (pt == NULL) { 99 SSHBUF_DBG(("SSH_ERR_ALLOC_FAIL")); 100 return SSH_ERR_ALLOC_FAIL; 101 } 102 if ((r = sshbuf_peek_string_direct(buf, &d, &len)) < 0) { 103 EC_POINT_free(pt); 104 return r; 105 } 106 if ((r = get_ec(d, len, pt, EC_KEY_get0_group(v))) != 0) { 107 EC_POINT_free(pt); 108 return r; 109 } 110 if (EC_KEY_set_public_key(v, pt) != 1) { 111 EC_POINT_free(pt); 112 return SSH_ERR_ALLOC_FAIL; /* XXX assumption */ 113 } 114 EC_POINT_free(pt); 115 /* Skip string */ 116 if (sshbuf_get_string_direct(buf, NULL, NULL) != 0) { 117 /* Shouldn't happen */ 118 SSHBUF_DBG(("SSH_ERR_INTERNAL_ERROR")); 119 SSHBUF_ABORT(); 120 return SSH_ERR_INTERNAL_ERROR; 121 } 122 return 0; 123} 124 125int 126sshbuf_put_bignum2(struct sshbuf *buf, const BIGNUM *v) 127{ 128 u_char d[SSHBUF_MAX_BIGNUM + 1]; 129 int len = BN_num_bytes(v), prepend = 0, r; 130 131 if (len < 0 || len > SSHBUF_MAX_BIGNUM) 132 return SSH_ERR_INVALID_ARGUMENT; 133 *d = '\0'; 134 if (BN_bn2bin(v, d + 1) != len) 135 return SSH_ERR_INTERNAL_ERROR; /* Shouldn't happen */ 136 /* If MSB is set, prepend a \0 */ 137 if (len > 0 && (d[1] & 0x80) != 0) 138 prepend = 1; 139 if ((r = sshbuf_put_string(buf, d + 1 - prepend, len + prepend)) < 0) { 140 explicit_bzero(d, sizeof(d)); 141 return r; 142 } 143 explicit_bzero(d, sizeof(d)); 144 return 0; 145} 146 147int 148sshbuf_put_ec(struct sshbuf *buf, const EC_POINT *v, const EC_GROUP *g) 149{ 150 u_char d[SSHBUF_MAX_ECPOINT]; 151 size_t len; 152 int ret; 153 154 if ((len = EC_POINT_point2oct(g, v, POINT_CONVERSION_UNCOMPRESSED, 155 NULL, 0, NULL)) > SSHBUF_MAX_ECPOINT) { 156 return SSH_ERR_INVALID_ARGUMENT; 157 } 158 if (EC_POINT_point2oct(g, v, POINT_CONVERSION_UNCOMPRESSED, 159 d, len, NULL) != len) { 160 return SSH_ERR_INTERNAL_ERROR; /* Shouldn't happen */ 161 } 162 ret = sshbuf_put_string(buf, d, len); 163 explicit_bzero(d, len); 164 return ret; 165} 166 167int 168sshbuf_put_eckey(struct sshbuf *buf, const EC_KEY *v) 169{ 170 return sshbuf_put_ec(buf, EC_KEY_get0_public_key(v), 171 EC_KEY_get0_group(v)); 172} 173 174