Coverage Report

Created: 2026-08-13 07:14

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