xref: /freebsd/crypto/openssh/sshbuf-getput-crypto.c (revision a91a246563dffa876a52f53a98de4af9fa364c52)
1*a91a2465SEd Maste /*	$OpenBSD: sshbuf-getput-crypto.c,v 1.11 2024/02/01 02:37:33 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 
2619261079SEd Maste #ifdef WITH_OPENSSL
27a0ee8cc6SDag-Erling Smørgrav #include <openssl/bn.h>
28a0ee8cc6SDag-Erling Smørgrav #ifdef OPENSSL_HAS_ECC
29a0ee8cc6SDag-Erling Smørgrav # include <openssl/ec.h>
30a0ee8cc6SDag-Erling Smørgrav #endif /* OPENSSL_HAS_ECC */
31a0ee8cc6SDag-Erling Smørgrav 
32a0ee8cc6SDag-Erling Smørgrav #include "ssherr.h"
33a0ee8cc6SDag-Erling Smørgrav #include "sshbuf.h"
34a0ee8cc6SDag-Erling Smørgrav 
35a0ee8cc6SDag-Erling Smørgrav int
sshbuf_get_bignum2(struct sshbuf * buf,BIGNUM ** valp)3619261079SEd Maste sshbuf_get_bignum2(struct sshbuf *buf, BIGNUM **valp)
37a0ee8cc6SDag-Erling Smørgrav {
3819261079SEd Maste 	BIGNUM *v;
39a0ee8cc6SDag-Erling Smørgrav 	const u_char *d;
40a0ee8cc6SDag-Erling Smørgrav 	size_t len;
41a0ee8cc6SDag-Erling Smørgrav 	int r;
42a0ee8cc6SDag-Erling Smørgrav 
4319261079SEd Maste 	if (valp != NULL)
4419261079SEd Maste 		*valp = NULL;
45bc5531deSDag-Erling Smørgrav 	if ((r = sshbuf_get_bignum2_bytes_direct(buf, &d, &len)) != 0)
46a0ee8cc6SDag-Erling Smørgrav 		return r;
4719261079SEd Maste 	if (valp != NULL) {
4819261079SEd Maste 		if ((v = BN_new()) == NULL ||
4919261079SEd Maste 		    BN_bin2bn(d, len, v) == NULL) {
5019261079SEd Maste 			BN_clear_free(v);
51a0ee8cc6SDag-Erling Smørgrav 			return SSH_ERR_ALLOC_FAIL;
52a0ee8cc6SDag-Erling Smørgrav 		}
5319261079SEd Maste 		*valp = v;
54a0ee8cc6SDag-Erling Smørgrav 	}
55a0ee8cc6SDag-Erling Smørgrav 	return 0;
56a0ee8cc6SDag-Erling Smørgrav }
57a0ee8cc6SDag-Erling Smørgrav 
58a0ee8cc6SDag-Erling Smørgrav #ifdef OPENSSL_HAS_ECC
59a0ee8cc6SDag-Erling Smørgrav static int
get_ec(const u_char * d,size_t len,EC_POINT * v,const EC_GROUP * g)60a0ee8cc6SDag-Erling Smørgrav get_ec(const u_char *d, size_t len, EC_POINT *v, const EC_GROUP *g)
61a0ee8cc6SDag-Erling Smørgrav {
62a0ee8cc6SDag-Erling Smørgrav 	/* Refuse overlong bignums */
63a0ee8cc6SDag-Erling Smørgrav 	if (len == 0 || len > SSHBUF_MAX_ECPOINT)
64a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_ECPOINT_TOO_LARGE;
65a0ee8cc6SDag-Erling Smørgrav 	/* Only handle uncompressed points */
66a0ee8cc6SDag-Erling Smørgrav 	if (*d != POINT_CONVERSION_UNCOMPRESSED)
67a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_INVALID_FORMAT;
68a0ee8cc6SDag-Erling Smørgrav 	if (v != NULL && EC_POINT_oct2point(g, v, d, len, NULL) != 1)
69a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_INVALID_FORMAT; /* XXX assumption */
70a0ee8cc6SDag-Erling Smørgrav 	return 0;
71a0ee8cc6SDag-Erling Smørgrav }
72a0ee8cc6SDag-Erling Smørgrav 
73a0ee8cc6SDag-Erling Smørgrav int
sshbuf_get_ec(struct sshbuf * buf,EC_POINT * v,const EC_GROUP * g)74a0ee8cc6SDag-Erling Smørgrav sshbuf_get_ec(struct sshbuf *buf, EC_POINT *v, const EC_GROUP *g)
75a0ee8cc6SDag-Erling Smørgrav {
76a0ee8cc6SDag-Erling Smørgrav 	const u_char *d;
77a0ee8cc6SDag-Erling Smørgrav 	size_t len;
78a0ee8cc6SDag-Erling Smørgrav 	int r;
79a0ee8cc6SDag-Erling Smørgrav 
80a0ee8cc6SDag-Erling Smørgrav 	if ((r = sshbuf_peek_string_direct(buf, &d, &len)) < 0)
81a0ee8cc6SDag-Erling Smørgrav 		return r;
82a0ee8cc6SDag-Erling Smørgrav 	if ((r = get_ec(d, len, v, g)) != 0)
83a0ee8cc6SDag-Erling Smørgrav 		return r;
84a0ee8cc6SDag-Erling Smørgrav 	/* Skip string */
85a0ee8cc6SDag-Erling Smørgrav 	if (sshbuf_get_string_direct(buf, NULL, NULL) != 0) {
86a0ee8cc6SDag-Erling Smørgrav 		/* Shouldn't happen */
87a0ee8cc6SDag-Erling Smørgrav 		SSHBUF_DBG(("SSH_ERR_INTERNAL_ERROR"));
88a0ee8cc6SDag-Erling Smørgrav 		SSHBUF_ABORT();
89a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_INTERNAL_ERROR;
90a0ee8cc6SDag-Erling Smørgrav 	}
91a0ee8cc6SDag-Erling Smørgrav 	return 0;
92a0ee8cc6SDag-Erling Smørgrav }
93a0ee8cc6SDag-Erling Smørgrav 
94a0ee8cc6SDag-Erling Smørgrav int
sshbuf_get_eckey(struct sshbuf * buf,EC_KEY * v)95a0ee8cc6SDag-Erling Smørgrav sshbuf_get_eckey(struct sshbuf *buf, EC_KEY *v)
96a0ee8cc6SDag-Erling Smørgrav {
97a0ee8cc6SDag-Erling Smørgrav 	EC_POINT *pt = EC_POINT_new(EC_KEY_get0_group(v));
98a0ee8cc6SDag-Erling Smørgrav 	int r;
99a0ee8cc6SDag-Erling Smørgrav 	const u_char *d;
100a0ee8cc6SDag-Erling Smørgrav 	size_t len;
101a0ee8cc6SDag-Erling Smørgrav 
102a0ee8cc6SDag-Erling Smørgrav 	if (pt == NULL) {
103a0ee8cc6SDag-Erling Smørgrav 		SSHBUF_DBG(("SSH_ERR_ALLOC_FAIL"));
104a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_ALLOC_FAIL;
105a0ee8cc6SDag-Erling Smørgrav 	}
106a0ee8cc6SDag-Erling Smørgrav 	if ((r = sshbuf_peek_string_direct(buf, &d, &len)) < 0) {
107a0ee8cc6SDag-Erling Smørgrav 		EC_POINT_free(pt);
108a0ee8cc6SDag-Erling Smørgrav 		return r;
109a0ee8cc6SDag-Erling Smørgrav 	}
110a0ee8cc6SDag-Erling Smørgrav 	if ((r = get_ec(d, len, pt, EC_KEY_get0_group(v))) != 0) {
111a0ee8cc6SDag-Erling Smørgrav 		EC_POINT_free(pt);
112a0ee8cc6SDag-Erling Smørgrav 		return r;
113a0ee8cc6SDag-Erling Smørgrav 	}
114a0ee8cc6SDag-Erling Smørgrav 	if (EC_KEY_set_public_key(v, pt) != 1) {
115a0ee8cc6SDag-Erling Smørgrav 		EC_POINT_free(pt);
116a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_ALLOC_FAIL; /* XXX assumption */
117a0ee8cc6SDag-Erling Smørgrav 	}
118a0ee8cc6SDag-Erling Smørgrav 	EC_POINT_free(pt);
119a0ee8cc6SDag-Erling Smørgrav 	/* Skip string */
120a0ee8cc6SDag-Erling Smørgrav 	if (sshbuf_get_string_direct(buf, NULL, NULL) != 0) {
121a0ee8cc6SDag-Erling Smørgrav 		/* Shouldn't happen */
122a0ee8cc6SDag-Erling Smørgrav 		SSHBUF_DBG(("SSH_ERR_INTERNAL_ERROR"));
123a0ee8cc6SDag-Erling Smørgrav 		SSHBUF_ABORT();
124a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_INTERNAL_ERROR;
125a0ee8cc6SDag-Erling Smørgrav 	}
126a0ee8cc6SDag-Erling Smørgrav 	return 0;
127a0ee8cc6SDag-Erling Smørgrav }
128a0ee8cc6SDag-Erling Smørgrav #endif /* OPENSSL_HAS_ECC */
129a0ee8cc6SDag-Erling Smørgrav 
130a0ee8cc6SDag-Erling Smørgrav int
sshbuf_put_bignum2(struct sshbuf * buf,const BIGNUM * v)131a0ee8cc6SDag-Erling Smørgrav sshbuf_put_bignum2(struct sshbuf *buf, const BIGNUM *v)
132a0ee8cc6SDag-Erling Smørgrav {
133a0ee8cc6SDag-Erling Smørgrav 	u_char d[SSHBUF_MAX_BIGNUM + 1];
134a0ee8cc6SDag-Erling Smørgrav 	int len = BN_num_bytes(v), prepend = 0, r;
135a0ee8cc6SDag-Erling Smørgrav 
136a0ee8cc6SDag-Erling Smørgrav 	if (len < 0 || len > SSHBUF_MAX_BIGNUM)
137a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_INVALID_ARGUMENT;
138a0ee8cc6SDag-Erling Smørgrav 	*d = '\0';
139a0ee8cc6SDag-Erling Smørgrav 	if (BN_bn2bin(v, d + 1) != len)
140a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_INTERNAL_ERROR; /* Shouldn't happen */
141a0ee8cc6SDag-Erling Smørgrav 	/* If MSB is set, prepend a \0 */
142a0ee8cc6SDag-Erling Smørgrav 	if (len > 0 && (d[1] & 0x80) != 0)
143a0ee8cc6SDag-Erling Smørgrav 		prepend = 1;
144a0ee8cc6SDag-Erling Smørgrav 	if ((r = sshbuf_put_string(buf, d + 1 - prepend, len + prepend)) < 0) {
145fc1ba28aSDag-Erling Smørgrav 		explicit_bzero(d, sizeof(d));
146a0ee8cc6SDag-Erling Smørgrav 		return r;
147a0ee8cc6SDag-Erling Smørgrav 	}
148fc1ba28aSDag-Erling Smørgrav 	explicit_bzero(d, sizeof(d));
149a0ee8cc6SDag-Erling Smørgrav 	return 0;
150a0ee8cc6SDag-Erling Smørgrav }
151a0ee8cc6SDag-Erling Smørgrav 
152a0ee8cc6SDag-Erling Smørgrav #ifdef OPENSSL_HAS_ECC
153a0ee8cc6SDag-Erling Smørgrav int
sshbuf_put_ec(struct sshbuf * buf,const EC_POINT * v,const EC_GROUP * g)154a0ee8cc6SDag-Erling Smørgrav sshbuf_put_ec(struct sshbuf *buf, const EC_POINT *v, const EC_GROUP *g)
155a0ee8cc6SDag-Erling Smørgrav {
156a0ee8cc6SDag-Erling Smørgrav 	u_char d[SSHBUF_MAX_ECPOINT];
157a0ee8cc6SDag-Erling Smørgrav 	size_t len;
158a0ee8cc6SDag-Erling Smørgrav 	int ret;
159a0ee8cc6SDag-Erling Smørgrav 
160a0ee8cc6SDag-Erling Smørgrav 	if ((len = EC_POINT_point2oct(g, v, POINT_CONVERSION_UNCOMPRESSED,
16119261079SEd Maste 	    NULL, 0, NULL)) > SSHBUF_MAX_ECPOINT) {
162a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_INVALID_ARGUMENT;
163a0ee8cc6SDag-Erling Smørgrav 	}
164a0ee8cc6SDag-Erling Smørgrav 	if (EC_POINT_point2oct(g, v, POINT_CONVERSION_UNCOMPRESSED,
16519261079SEd Maste 	    d, len, NULL) != len) {
166a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_INTERNAL_ERROR; /* Shouldn't happen */
167a0ee8cc6SDag-Erling Smørgrav 	}
168a0ee8cc6SDag-Erling Smørgrav 	ret = sshbuf_put_string(buf, d, len);
169fc1ba28aSDag-Erling Smørgrav 	explicit_bzero(d, len);
170a0ee8cc6SDag-Erling Smørgrav 	return ret;
171a0ee8cc6SDag-Erling Smørgrav }
172a0ee8cc6SDag-Erling Smørgrav 
173a0ee8cc6SDag-Erling Smørgrav int
sshbuf_put_eckey(struct sshbuf * buf,const EC_KEY * v)174a0ee8cc6SDag-Erling Smørgrav sshbuf_put_eckey(struct sshbuf *buf, const EC_KEY *v)
175a0ee8cc6SDag-Erling Smørgrav {
176a0ee8cc6SDag-Erling Smørgrav 	return sshbuf_put_ec(buf, EC_KEY_get0_public_key(v),
177a0ee8cc6SDag-Erling Smørgrav 	    EC_KEY_get0_group(v));
178a0ee8cc6SDag-Erling Smørgrav }
179a0ee8cc6SDag-Erling Smørgrav #endif /* OPENSSL_HAS_ECC */
18019261079SEd Maste #endif /* WITH_OPENSSL */
181