xref: /openbsd-src/usr.bin/ssh/sshbuf-getput-crypto.c (revision 5411e7691687441b2e28282ca3a1c531c6b949c4)
1*5411e769Sdjm /*	$OpenBSD: sshbuf-getput-crypto.c,v 1.12 2024/08/15 00:51:51 djm Exp $	*/
215b55daeSdjm /*
315b55daeSdjm  * Copyright (c) 2011 Damien Miller
415b55daeSdjm  *
515b55daeSdjm  * Permission to use, copy, modify, and distribute this software for any
615b55daeSdjm  * purpose with or without fee is hereby granted, provided that the above
715b55daeSdjm  * copyright notice and this permission notice appear in all copies.
815b55daeSdjm  *
915b55daeSdjm  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1015b55daeSdjm  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1115b55daeSdjm  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1215b55daeSdjm  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1315b55daeSdjm  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1415b55daeSdjm  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1515b55daeSdjm  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1615b55daeSdjm  */
1715b55daeSdjm 
1815b55daeSdjm #include <sys/types.h>
1915b55daeSdjm #include <stdlib.h>
2015b55daeSdjm #include <stdio.h>
2115b55daeSdjm #include <string.h>
2215b55daeSdjm 
2315b55daeSdjm #include <openssl/bn.h>
2415b55daeSdjm #include <openssl/ec.h>
2515b55daeSdjm 
2615b55daeSdjm #include "ssherr.h"
2715b55daeSdjm #define SSHBUF_INTERNAL
2815b55daeSdjm #include "sshbuf.h"
2915b55daeSdjm 
3015b55daeSdjm int
31f37f3ee2Sdjm sshbuf_get_bignum2(struct sshbuf *buf, BIGNUM **valp)
3215b55daeSdjm {
33f37f3ee2Sdjm 	BIGNUM *v;
3415b55daeSdjm 	const u_char *d;
3515b55daeSdjm 	size_t len;
3615b55daeSdjm 	int r;
3715b55daeSdjm 
38f37f3ee2Sdjm 	if (valp != NULL)
39f37f3ee2Sdjm 		*valp = NULL;
4078e9a853Sdjm 	if ((r = sshbuf_get_bignum2_bytes_direct(buf, &d, &len)) != 0)
4115b55daeSdjm 		return r;
42f37f3ee2Sdjm 	if (valp != NULL) {
43f37f3ee2Sdjm 		if ((v = BN_new()) == NULL ||
44f37f3ee2Sdjm 		    BN_bin2bn(d, len, v) == NULL) {
45f37f3ee2Sdjm 			BN_clear_free(v);
4615b55daeSdjm 			return SSH_ERR_ALLOC_FAIL;
47f37f3ee2Sdjm 		}
48f37f3ee2Sdjm 		*valp = v;
49f37f3ee2Sdjm 	}
5015b55daeSdjm 	return 0;
5115b55daeSdjm }
5215b55daeSdjm 
5315b55daeSdjm static int
5415b55daeSdjm get_ec(const u_char *d, size_t len, EC_POINT *v, const EC_GROUP *g)
5515b55daeSdjm {
5615b55daeSdjm 	/* Refuse overlong bignums */
5715b55daeSdjm 	if (len == 0 || len > SSHBUF_MAX_ECPOINT)
5815b55daeSdjm 		return SSH_ERR_ECPOINT_TOO_LARGE;
5915b55daeSdjm 	/* Only handle uncompressed points */
6015b55daeSdjm 	if (*d != POINT_CONVERSION_UNCOMPRESSED)
6115b55daeSdjm 		return SSH_ERR_INVALID_FORMAT;
6215b55daeSdjm 	if (v != NULL && EC_POINT_oct2point(g, v, d, len, NULL) != 1)
6315b55daeSdjm 		return SSH_ERR_INVALID_FORMAT; /* XXX assumption */
6415b55daeSdjm 	return 0;
6515b55daeSdjm }
6615b55daeSdjm 
6715b55daeSdjm int
6815b55daeSdjm sshbuf_get_ec(struct sshbuf *buf, EC_POINT *v, const EC_GROUP *g)
6915b55daeSdjm {
7015b55daeSdjm 	const u_char *d;
7115b55daeSdjm 	size_t len;
7215b55daeSdjm 	int r;
7315b55daeSdjm 
7415b55daeSdjm 	if ((r = sshbuf_peek_string_direct(buf, &d, &len)) < 0)
7515b55daeSdjm 		return r;
7615b55daeSdjm 	if ((r = get_ec(d, len, v, g)) != 0)
7715b55daeSdjm 		return r;
7815b55daeSdjm 	/* Skip string */
7915b55daeSdjm 	if (sshbuf_get_string_direct(buf, NULL, NULL) != 0) {
8015b55daeSdjm 		/* Shouldn't happen */
81a8cbed27Sdjm 		SSHBUF_DBG(("SSH_ERR_INTERNAL_ERROR"));
8215b55daeSdjm 		SSHBUF_ABORT();
8315b55daeSdjm 		return SSH_ERR_INTERNAL_ERROR;
8415b55daeSdjm 	}
8515b55daeSdjm 	return 0;
8615b55daeSdjm }
8715b55daeSdjm 
8815b55daeSdjm int
8915b55daeSdjm sshbuf_get_eckey(struct sshbuf *buf, EC_KEY *v)
9015b55daeSdjm {
9115b55daeSdjm 	EC_POINT *pt = EC_POINT_new(EC_KEY_get0_group(v));
9215b55daeSdjm 	int r;
9315b55daeSdjm 	const u_char *d;
9415b55daeSdjm 	size_t len;
9515b55daeSdjm 
9615b55daeSdjm 	if (pt == NULL) {
97a8cbed27Sdjm 		SSHBUF_DBG(("SSH_ERR_ALLOC_FAIL"));
9815b55daeSdjm 		return SSH_ERR_ALLOC_FAIL;
9915b55daeSdjm 	}
10015b55daeSdjm 	if ((r = sshbuf_peek_string_direct(buf, &d, &len)) < 0) {
10115b55daeSdjm 		EC_POINT_free(pt);
10215b55daeSdjm 		return r;
10315b55daeSdjm 	}
10415b55daeSdjm 	if ((r = get_ec(d, len, pt, EC_KEY_get0_group(v))) != 0) {
10515b55daeSdjm 		EC_POINT_free(pt);
10615b55daeSdjm 		return r;
10715b55daeSdjm 	}
10815b55daeSdjm 	if (EC_KEY_set_public_key(v, pt) != 1) {
10915b55daeSdjm 		EC_POINT_free(pt);
11015b55daeSdjm 		return SSH_ERR_ALLOC_FAIL; /* XXX assumption */
11115b55daeSdjm 	}
11215b55daeSdjm 	EC_POINT_free(pt);
11315b55daeSdjm 	/* Skip string */
11415b55daeSdjm 	if (sshbuf_get_string_direct(buf, NULL, NULL) != 0) {
11515b55daeSdjm 		/* Shouldn't happen */
116a8cbed27Sdjm 		SSHBUF_DBG(("SSH_ERR_INTERNAL_ERROR"));
11715b55daeSdjm 		SSHBUF_ABORT();
11815b55daeSdjm 		return SSH_ERR_INTERNAL_ERROR;
11915b55daeSdjm 	}
12015b55daeSdjm 	return 0;
12115b55daeSdjm }
12215b55daeSdjm 
12315b55daeSdjm int
12415b55daeSdjm sshbuf_put_bignum2(struct sshbuf *buf, const BIGNUM *v)
12515b55daeSdjm {
12615b55daeSdjm 	u_char d[SSHBUF_MAX_BIGNUM + 1];
12715b55daeSdjm 	int len = BN_num_bytes(v), prepend = 0, r;
12815b55daeSdjm 
12915b55daeSdjm 	if (len < 0 || len > SSHBUF_MAX_BIGNUM)
13015b55daeSdjm 		return SSH_ERR_INVALID_ARGUMENT;
13115b55daeSdjm 	*d = '\0';
13215b55daeSdjm 	if (BN_bn2bin(v, d + 1) != len)
13315b55daeSdjm 		return SSH_ERR_INTERNAL_ERROR; /* Shouldn't happen */
13415b55daeSdjm 	/* If MSB is set, prepend a \0 */
13515b55daeSdjm 	if (len > 0 && (d[1] & 0x80) != 0)
13615b55daeSdjm 		prepend = 1;
13715b55daeSdjm 	if ((r = sshbuf_put_string(buf, d + 1 - prepend, len + prepend)) < 0) {
1385c47a739Sdjm 		explicit_bzero(d, sizeof(d));
13915b55daeSdjm 		return r;
14015b55daeSdjm 	}
1415c47a739Sdjm 	explicit_bzero(d, sizeof(d));
14215b55daeSdjm 	return 0;
14315b55daeSdjm }
14415b55daeSdjm 
14515b55daeSdjm int
14615b55daeSdjm sshbuf_put_ec(struct sshbuf *buf, const EC_POINT *v, const EC_GROUP *g)
14715b55daeSdjm {
14815b55daeSdjm 	u_char d[SSHBUF_MAX_ECPOINT];
14915b55daeSdjm 	size_t len;
15015b55daeSdjm 	int ret;
15115b55daeSdjm 
15215b55daeSdjm 	if ((len = EC_POINT_point2oct(g, v, POINT_CONVERSION_UNCOMPRESSED,
15307b718edSdjm 	    NULL, 0, NULL)) > SSHBUF_MAX_ECPOINT) {
15415b55daeSdjm 		return SSH_ERR_INVALID_ARGUMENT;
15515b55daeSdjm 	}
15615b55daeSdjm 	if (EC_POINT_point2oct(g, v, POINT_CONVERSION_UNCOMPRESSED,
15707b718edSdjm 	    d, len, NULL) != len) {
15815b55daeSdjm 		return SSH_ERR_INTERNAL_ERROR; /* Shouldn't happen */
15915b55daeSdjm 	}
16015b55daeSdjm 	ret = sshbuf_put_string(buf, d, len);
1615c47a739Sdjm 	explicit_bzero(d, len);
16215b55daeSdjm 	return ret;
16315b55daeSdjm }
16415b55daeSdjm 
16515b55daeSdjm int
16615b55daeSdjm sshbuf_put_eckey(struct sshbuf *buf, const EC_KEY *v)
16715b55daeSdjm {
16815b55daeSdjm 	return sshbuf_put_ec(buf, EC_KEY_get0_public_key(v),
16915b55daeSdjm 	    EC_KEY_get0_group(v));
17015b55daeSdjm }
17115b55daeSdjm 
172*5411e769Sdjm int
173*5411e769Sdjm sshbuf_put_ec_pkey(struct sshbuf *buf, EVP_PKEY *pkey)
174*5411e769Sdjm {
175*5411e769Sdjm 	const EC_KEY *ec;
176*5411e769Sdjm 
177*5411e769Sdjm 	if ((ec = EVP_PKEY_get0_EC_KEY(pkey)) == NULL)
178*5411e769Sdjm 		return SSH_ERR_LIBCRYPTO_ERROR;
179*5411e769Sdjm 	return sshbuf_put_eckey(buf, ec);
180*5411e769Sdjm }
181