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