1 /* $OpenBSD: ssh-dss.c,v 1.49 2023/03/05 05:34:09 dtucker Exp $ */ 2 /* 3 * Copyright (c) 2000 Markus Friedl. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #include <sys/types.h> 27 28 #include <openssl/bn.h> 29 #include <openssl/evp.h> 30 31 #include <string.h> 32 33 #include "sshbuf.h" 34 #include "ssherr.h" 35 #include "digest.h" 36 #define SSHKEY_INTERNAL 37 #include "sshkey.h" 38 39 #define INTBLOB_LEN 20 40 #define SIGBLOB_LEN (2*INTBLOB_LEN) 41 42 static u_int 43 ssh_dss_size(const struct sshkey *key) 44 { 45 const BIGNUM *dsa_p; 46 47 if (key->dsa == NULL) 48 return 0; 49 DSA_get0_pqg(key->dsa, &dsa_p, NULL, NULL); 50 return BN_num_bits(dsa_p); 51 } 52 53 static int 54 ssh_dss_alloc(struct sshkey *k) 55 { 56 if ((k->dsa = DSA_new()) == NULL) 57 return SSH_ERR_ALLOC_FAIL; 58 return 0; 59 } 60 61 static void 62 ssh_dss_cleanup(struct sshkey *k) 63 { 64 DSA_free(k->dsa); 65 k->dsa = NULL; 66 } 67 68 static int 69 ssh_dss_equal(const struct sshkey *a, const struct sshkey *b) 70 { 71 const BIGNUM *dsa_p_a, *dsa_q_a, *dsa_g_a, *dsa_pub_key_a; 72 const BIGNUM *dsa_p_b, *dsa_q_b, *dsa_g_b, *dsa_pub_key_b; 73 74 if (a->dsa == NULL || b->dsa == NULL) 75 return 0; 76 DSA_get0_pqg(a->dsa, &dsa_p_a, &dsa_q_a, &dsa_g_a); 77 DSA_get0_pqg(b->dsa, &dsa_p_b, &dsa_q_b, &dsa_g_b); 78 DSA_get0_key(a->dsa, &dsa_pub_key_a, NULL); 79 DSA_get0_key(b->dsa, &dsa_pub_key_b, NULL); 80 if (dsa_p_a == NULL || dsa_p_b == NULL || 81 dsa_q_a == NULL || dsa_q_b == NULL || 82 dsa_g_a == NULL || dsa_g_b == NULL || 83 dsa_pub_key_a == NULL || dsa_pub_key_b == NULL) 84 return 0; 85 if (BN_cmp(dsa_p_a, dsa_p_b) != 0) 86 return 0; 87 if (BN_cmp(dsa_q_a, dsa_q_b) != 0) 88 return 0; 89 if (BN_cmp(dsa_g_a, dsa_g_b) != 0) 90 return 0; 91 if (BN_cmp(dsa_pub_key_a, dsa_pub_key_b) != 0) 92 return 0; 93 return 1; 94 } 95 96 static int 97 ssh_dss_serialize_public(const struct sshkey *key, struct sshbuf *b, 98 enum sshkey_serialize_rep opts) 99 { 100 int r; 101 const BIGNUM *dsa_p, *dsa_q, *dsa_g, *dsa_pub_key; 102 103 if (key->dsa == NULL) 104 return SSH_ERR_INVALID_ARGUMENT; 105 DSA_get0_pqg(key->dsa, &dsa_p, &dsa_q, &dsa_g); 106 DSA_get0_key(key->dsa, &dsa_pub_key, NULL); 107 if (dsa_p == NULL || dsa_q == NULL || 108 dsa_g == NULL || dsa_pub_key == NULL) 109 return SSH_ERR_INTERNAL_ERROR; 110 if ((r = sshbuf_put_bignum2(b, dsa_p)) != 0 || 111 (r = sshbuf_put_bignum2(b, dsa_q)) != 0 || 112 (r = sshbuf_put_bignum2(b, dsa_g)) != 0 || 113 (r = sshbuf_put_bignum2(b, dsa_pub_key)) != 0) 114 return r; 115 116 return 0; 117 } 118 119 static int 120 ssh_dss_serialize_private(const struct sshkey *key, struct sshbuf *b, 121 enum sshkey_serialize_rep opts) 122 { 123 int r; 124 const BIGNUM *dsa_priv_key; 125 126 DSA_get0_key(key->dsa, NULL, &dsa_priv_key); 127 if (!sshkey_is_cert(key)) { 128 if ((r = ssh_dss_serialize_public(key, b, opts)) != 0) 129 return r; 130 } 131 if ((r = sshbuf_put_bignum2(b, dsa_priv_key)) != 0) 132 return r; 133 134 return 0; 135 } 136 137 static int 138 ssh_dss_generate(struct sshkey *k, int bits) 139 { 140 DSA *private; 141 142 if (bits != 1024) 143 return SSH_ERR_KEY_LENGTH; 144 if ((private = DSA_new()) == NULL) 145 return SSH_ERR_ALLOC_FAIL; 146 if (!DSA_generate_parameters_ex(private, bits, NULL, 0, NULL, 147 NULL, NULL) || !DSA_generate_key(private)) { 148 DSA_free(private); 149 return SSH_ERR_LIBCRYPTO_ERROR; 150 } 151 k->dsa = private; 152 return 0; 153 } 154 155 static int 156 ssh_dss_copy_public(const struct sshkey *from, struct sshkey *to) 157 { 158 const BIGNUM *dsa_p, *dsa_q, *dsa_g, *dsa_pub_key; 159 BIGNUM *dsa_p_dup = NULL, *dsa_q_dup = NULL, *dsa_g_dup = NULL; 160 BIGNUM *dsa_pub_key_dup = NULL; 161 int r = SSH_ERR_INTERNAL_ERROR; 162 163 DSA_get0_pqg(from->dsa, &dsa_p, &dsa_q, &dsa_g); 164 DSA_get0_key(from->dsa, &dsa_pub_key, NULL); 165 if ((dsa_p_dup = BN_dup(dsa_p)) == NULL || 166 (dsa_q_dup = BN_dup(dsa_q)) == NULL || 167 (dsa_g_dup = BN_dup(dsa_g)) == NULL || 168 (dsa_pub_key_dup = BN_dup(dsa_pub_key)) == NULL) { 169 r = SSH_ERR_ALLOC_FAIL; 170 goto out; 171 } 172 if (!DSA_set0_pqg(to->dsa, dsa_p_dup, dsa_q_dup, dsa_g_dup)) { 173 r = SSH_ERR_LIBCRYPTO_ERROR; 174 goto out; 175 } 176 dsa_p_dup = dsa_q_dup = dsa_g_dup = NULL; /* transferred */ 177 if (!DSA_set0_key(to->dsa, dsa_pub_key_dup, NULL)) { 178 r = SSH_ERR_LIBCRYPTO_ERROR; 179 goto out; 180 } 181 dsa_pub_key_dup = NULL; /* transferred */ 182 /* success */ 183 r = 0; 184 out: 185 BN_clear_free(dsa_p_dup); 186 BN_clear_free(dsa_q_dup); 187 BN_clear_free(dsa_g_dup); 188 BN_clear_free(dsa_pub_key_dup); 189 return r; 190 } 191 192 static int 193 ssh_dss_deserialize_public(const char *ktype, struct sshbuf *b, 194 struct sshkey *key) 195 { 196 int ret = SSH_ERR_INTERNAL_ERROR; 197 BIGNUM *dsa_p = NULL, *dsa_q = NULL, *dsa_g = NULL, *dsa_pub_key = NULL; 198 199 if (sshbuf_get_bignum2(b, &dsa_p) != 0 || 200 sshbuf_get_bignum2(b, &dsa_q) != 0 || 201 sshbuf_get_bignum2(b, &dsa_g) != 0 || 202 sshbuf_get_bignum2(b, &dsa_pub_key) != 0) { 203 ret = SSH_ERR_INVALID_FORMAT; 204 goto out; 205 } 206 if (!DSA_set0_pqg(key->dsa, dsa_p, dsa_q, dsa_g)) { 207 ret = SSH_ERR_LIBCRYPTO_ERROR; 208 goto out; 209 } 210 dsa_p = dsa_q = dsa_g = NULL; /* transferred */ 211 if (!DSA_set0_key(key->dsa, dsa_pub_key, NULL)) { 212 ret = SSH_ERR_LIBCRYPTO_ERROR; 213 goto out; 214 } 215 dsa_pub_key = NULL; /* transferred */ 216 #ifdef DEBUG_PK 217 DSA_print_fp(stderr, key->dsa, 8); 218 #endif 219 /* success */ 220 ret = 0; 221 out: 222 BN_clear_free(dsa_p); 223 BN_clear_free(dsa_q); 224 BN_clear_free(dsa_g); 225 BN_clear_free(dsa_pub_key); 226 return ret; 227 } 228 229 static int 230 ssh_dss_deserialize_private(const char *ktype, struct sshbuf *b, 231 struct sshkey *key) 232 { 233 int r; 234 BIGNUM *dsa_priv_key = NULL; 235 236 if (!sshkey_is_cert(key)) { 237 if ((r = ssh_dss_deserialize_public(ktype, b, key)) != 0) 238 return r; 239 } 240 241 if ((r = sshbuf_get_bignum2(b, &dsa_priv_key)) != 0) 242 return r; 243 if (!DSA_set0_key(key->dsa, NULL, dsa_priv_key)) { 244 BN_clear_free(dsa_priv_key); 245 return SSH_ERR_LIBCRYPTO_ERROR; 246 } 247 return 0; 248 } 249 250 static int 251 ssh_dss_sign(struct sshkey *key, 252 u_char **sigp, size_t *lenp, 253 const u_char *data, size_t datalen, 254 const char *alg, const char *sk_provider, const char *sk_pin, u_int compat) 255 { 256 DSA_SIG *sig = NULL; 257 const BIGNUM *sig_r, *sig_s; 258 u_char digest[SSH_DIGEST_MAX_LENGTH], sigblob[SIGBLOB_LEN]; 259 size_t rlen, slen, len, dlen = ssh_digest_bytes(SSH_DIGEST_SHA1); 260 struct sshbuf *b = NULL; 261 int ret = SSH_ERR_INVALID_ARGUMENT; 262 263 if (lenp != NULL) 264 *lenp = 0; 265 if (sigp != NULL) 266 *sigp = NULL; 267 268 if (key == NULL || key->dsa == NULL || 269 sshkey_type_plain(key->type) != KEY_DSA) 270 return SSH_ERR_INVALID_ARGUMENT; 271 if (dlen == 0) 272 return SSH_ERR_INTERNAL_ERROR; 273 274 if ((ret = ssh_digest_memory(SSH_DIGEST_SHA1, data, datalen, 275 digest, sizeof(digest))) != 0) 276 goto out; 277 278 if ((sig = DSA_do_sign(digest, dlen, key->dsa)) == NULL) { 279 ret = SSH_ERR_LIBCRYPTO_ERROR; 280 goto out; 281 } 282 283 DSA_SIG_get0(sig, &sig_r, &sig_s); 284 rlen = BN_num_bytes(sig_r); 285 slen = BN_num_bytes(sig_s); 286 if (rlen > INTBLOB_LEN || slen > INTBLOB_LEN) { 287 ret = SSH_ERR_INTERNAL_ERROR; 288 goto out; 289 } 290 explicit_bzero(sigblob, SIGBLOB_LEN); 291 BN_bn2bin(sig_r, sigblob + SIGBLOB_LEN - INTBLOB_LEN - rlen); 292 BN_bn2bin(sig_s, sigblob + SIGBLOB_LEN - slen); 293 294 if ((b = sshbuf_new()) == NULL) { 295 ret = SSH_ERR_ALLOC_FAIL; 296 goto out; 297 } 298 if ((ret = sshbuf_put_cstring(b, "ssh-dss")) != 0 || 299 (ret = sshbuf_put_string(b, sigblob, SIGBLOB_LEN)) != 0) 300 goto out; 301 302 len = sshbuf_len(b); 303 if (sigp != NULL) { 304 if ((*sigp = malloc(len)) == NULL) { 305 ret = SSH_ERR_ALLOC_FAIL; 306 goto out; 307 } 308 memcpy(*sigp, sshbuf_ptr(b), len); 309 } 310 if (lenp != NULL) 311 *lenp = len; 312 ret = 0; 313 out: 314 explicit_bzero(digest, sizeof(digest)); 315 DSA_SIG_free(sig); 316 sshbuf_free(b); 317 return ret; 318 } 319 320 static int 321 ssh_dss_verify(const struct sshkey *key, 322 const u_char *sig, size_t siglen, 323 const u_char *data, size_t dlen, const char *alg, u_int compat, 324 struct sshkey_sig_details **detailsp) 325 { 326 DSA_SIG *dsig = NULL; 327 BIGNUM *sig_r = NULL, *sig_s = NULL; 328 u_char digest[SSH_DIGEST_MAX_LENGTH], *sigblob = NULL; 329 size_t len, hlen = ssh_digest_bytes(SSH_DIGEST_SHA1); 330 int ret = SSH_ERR_INTERNAL_ERROR; 331 struct sshbuf *b = NULL; 332 char *ktype = NULL; 333 334 if (key == NULL || key->dsa == NULL || 335 sshkey_type_plain(key->type) != KEY_DSA || 336 sig == NULL || siglen == 0) 337 return SSH_ERR_INVALID_ARGUMENT; 338 if (hlen == 0) 339 return SSH_ERR_INTERNAL_ERROR; 340 341 /* fetch signature */ 342 if ((b = sshbuf_from(sig, siglen)) == NULL) 343 return SSH_ERR_ALLOC_FAIL; 344 if (sshbuf_get_cstring(b, &ktype, NULL) != 0 || 345 sshbuf_get_string(b, &sigblob, &len) != 0) { 346 ret = SSH_ERR_INVALID_FORMAT; 347 goto out; 348 } 349 if (strcmp("ssh-dss", ktype) != 0) { 350 ret = SSH_ERR_KEY_TYPE_MISMATCH; 351 goto out; 352 } 353 if (sshbuf_len(b) != 0) { 354 ret = SSH_ERR_UNEXPECTED_TRAILING_DATA; 355 goto out; 356 } 357 358 if (len != SIGBLOB_LEN) { 359 ret = SSH_ERR_INVALID_FORMAT; 360 goto out; 361 } 362 363 /* parse signature */ 364 if ((dsig = DSA_SIG_new()) == NULL || 365 (sig_r = BN_new()) == NULL || 366 (sig_s = BN_new()) == NULL) { 367 ret = SSH_ERR_ALLOC_FAIL; 368 goto out; 369 } 370 if ((BN_bin2bn(sigblob, INTBLOB_LEN, sig_r) == NULL) || 371 (BN_bin2bn(sigblob + INTBLOB_LEN, INTBLOB_LEN, sig_s) == NULL)) { 372 ret = SSH_ERR_LIBCRYPTO_ERROR; 373 goto out; 374 } 375 if (!DSA_SIG_set0(dsig, sig_r, sig_s)) { 376 ret = SSH_ERR_LIBCRYPTO_ERROR; 377 goto out; 378 } 379 sig_r = sig_s = NULL; /* transferred */ 380 381 /* sha1 the data */ 382 if ((ret = ssh_digest_memory(SSH_DIGEST_SHA1, data, dlen, 383 digest, sizeof(digest))) != 0) 384 goto out; 385 386 switch (DSA_do_verify(digest, hlen, dsig, key->dsa)) { 387 case 1: 388 ret = 0; 389 break; 390 case 0: 391 ret = SSH_ERR_SIGNATURE_INVALID; 392 goto out; 393 default: 394 ret = SSH_ERR_LIBCRYPTO_ERROR; 395 goto out; 396 } 397 398 out: 399 explicit_bzero(digest, sizeof(digest)); 400 DSA_SIG_free(dsig); 401 BN_clear_free(sig_r); 402 BN_clear_free(sig_s); 403 sshbuf_free(b); 404 free(ktype); 405 if (sigblob != NULL) 406 freezero(sigblob, len); 407 return ret; 408 } 409 410 static const struct sshkey_impl_funcs sshkey_dss_funcs = { 411 /* .size = */ ssh_dss_size, 412 /* .alloc = */ ssh_dss_alloc, 413 /* .cleanup = */ ssh_dss_cleanup, 414 /* .equal = */ ssh_dss_equal, 415 /* .ssh_serialize_public = */ ssh_dss_serialize_public, 416 /* .ssh_deserialize_public = */ ssh_dss_deserialize_public, 417 /* .ssh_serialize_private = */ ssh_dss_serialize_private, 418 /* .ssh_deserialize_private = */ ssh_dss_deserialize_private, 419 /* .generate = */ ssh_dss_generate, 420 /* .copy_public = */ ssh_dss_copy_public, 421 /* .sign = */ ssh_dss_sign, 422 /* .verify = */ ssh_dss_verify, 423 }; 424 425 const struct sshkey_impl sshkey_dss_impl = { 426 /* .name = */ "ssh-dss", 427 /* .shortname = */ "DSA", 428 /* .sigalg = */ NULL, 429 /* .type = */ KEY_DSA, 430 /* .nid = */ 0, 431 /* .cert = */ 0, 432 /* .sigonly = */ 0, 433 /* .keybits = */ 0, 434 /* .funcs = */ &sshkey_dss_funcs, 435 }; 436 437 const struct sshkey_impl sshkey_dsa_cert_impl = { 438 /* .name = */ "ssh-dss-cert-v01@openssh.com", 439 /* .shortname = */ "DSA-CERT", 440 /* .sigalg = */ NULL, 441 /* .type = */ KEY_DSA_CERT, 442 /* .nid = */ 0, 443 /* .cert = */ 1, 444 /* .sigonly = */ 0, 445 /* .keybits = */ 0, 446 /* .funcs = */ &sshkey_dss_funcs, 447 }; 448