1 /* $OpenBSD: sshbuf-getput-crypto.c,v 1.12 2024/08/15 00:51:51 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.13 2024/09/24 21:32:19 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 32 int 33 sshbuf_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 55 static int 56 get_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 69 int 70 sshbuf_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 90 int 91 sshbuf_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 125 int 126 sshbuf_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 147 int 148 sshbuf_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 167 int 168 sshbuf_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 int 175 sshbuf_put_ec_pkey(struct sshbuf *buf, EVP_PKEY *pkey) 176 { 177 const EC_KEY *ec; 178 179 if ((ec = EVP_PKEY_get0_EC_KEY(pkey)) == NULL) 180 return SSH_ERR_LIBCRYPTO_ERROR; 181 return sshbuf_put_eckey(buf, ec); 182 } 183